javascript - 调用时 useState 不更新
问题描述
我正在建立一个餐厅网站模板。在项目中,我确实有一个带有两个箭头按钮的模式框来更改页面。pageNumber
我通过 useState跟踪变量。不幸的是,该值永远不会更新,这会阻止页面更改。
这是 Menu.js 组件:
import { BrowserRouter as Router, Link } from 'react-router-dom';
import { useState } from 'react';
const Menu = () => {
let [pageNumber, switchPage] = useState(1);
let dish = {
categories: [
'proin blandit',
'suspendisse non',
'fermentum ultrices',
'volutpat vulputat'
],
names: [
['Sed fermentum', 'Sapien nec lobortis', 'Tristique in suspendisse', 'Pellentesque mattis elit', 'Vel interdum velit'],
['Nam nisi quam', 'Donec non viverra', 'Morbi suscipit mattis', 'Sed dignissim nisi', 'Aliquam vitae'],
['Curabitur ante mi', 'Nulla a felis', 'Donec porta convallis ', 'Vestibulum viverra ', 'Nullam viverra '],
['Vestibulum odio', 'Mauris neque ligula', 'Praesent iaculis nunc', 'Cras sollicitudin est', 'Class aptent taciti ']
],
prices: [
[13.99, 11.99, 15.99, 17.99, 21.99],
[22.99, 20.99, 18.99, 16.99, 24.99],
[11.99, 21.99, 31.99, 25.99, 15.99],
[6.99, 8.99, 10.99, 4.99, 8.99]
]
}
let iterator = Math.abs(pageNumber % 4);
let lineBreak = window.innerWidth <= 750 ? <br/> : undefined;
return (
<Router>
<section className='menu'>
<i className='fas fa-chevron-circle-left' id='menu-arrow-left' onClick={() => switchPage(pageNumber - 1)}></i>
<h1 className='dish-category'>You are viewing {dish.categories[iterator]}</h1>
<Link to='/home'><i className='fas fa-times'></i></Link>
<ul className='dish-list'>
<li className='dish'>{dish.names[iterator][0]} {lineBreak} <span className='price'>{dish.prices[iterator][0]} PLN</span></li>
<li className='dish'>{dish.names[iterator][1]} {lineBreak} <span className='price'>{dish.prices[iterator][1]} PLN</span></li>
<li className='dish'>{dish.names[iterator][2]} {lineBreak} <span className='price'>{dish.prices[iterator][2]} PLN</span></li>
<li className='dish'>{dish.names[iterator][3]} {lineBreak} <span className='price'>{dish.prices[iterator][3]} PLN</span></li>
<li className='dish'>{dish.names[iterator][4]} {lineBreak} <span className='price'>{dish.prices[iterator][4]} PLN</span></li>
</ul>
<i className='fas fa-chevron-circle-right' id='menu-arrow-right' onClick={() => switchPage(pageNumber + 1)}></i>
</section>
</Router>
)
}
export default Menu;
这就是我切换模式可见性的方式:
const hideModal = (e) => {
e.preventDefault();
let placeholder = document.getElementById('placeholder');
placeholder.innerText = '';
placeholder.style.display = 'none';
let container = document.getElementById('container');
container.style.filter = '';
container.style.pointerEvents = 'auto';
}
const showModal = () => {
let placeholder = document.getElementById('placeholder');
placeholder.innerHTML = ReactDOMServer.renderToString(<Menu />);
placeholder.style.display = 'block';
let container = document.getElementById('container');
container.style.filter = 'blur(8px)';
container.style.pointerEvents = 'none';
}
这是 App.js 中对应的 JSX 代码:
<div id='placeholder'><Menu /> <Contact /></div>
此外,我编写了一个检测点击位置的测试函数。当我在上面的示例中运行它时,我收到一条消息,我在模式框外单击,即使它是相反的。该函数从不同的文件运行。它看起来像这样:
let childrenNodes = [
document.getElementsByClassName('menu')[0],
document.getElementsByClassName('dish-category')[0],
document.getElementsByClassName('dish-list')[0],
document.getElementsByClassName('dish')[0],
document.getElementsByClassName('dish')[1],
document.getElementsByClassName('dish')[2],
document.getElementsByClassName('dish')[3],
document.getElementsByClassName('dish')[4],
document.getElementsByClassName('price')[0],
document.getElementsByClassName('price')[1],
document.getElementsByClassName('price')[2],
document.getElementsByClassName('price')[3],
document.getElementsByClassName('price')[4]
];
const detectPlace = () => {
window.addEventListener('click', (e) => {
childrenNodes.some((node) => e.target === node) ? console.log('Clicked inside!') : console.log('Clicked outside!');
console.log(e.target);
});
}
你能告诉我为什么它会这样工作吗?
解决方案
您正在渲染以下内容#placholder
:
let placeholder = document.getElementById('placeholder');
placeholder.innerHTML = ReactDOMServer.renderToString(<Menu />);
ReactDOMServer.renderToString(...)
生成一个包含 HTML 的字符串。此字符串不包含任何 JavaScript,因此使结果非交互式。
渲染字符串()
ReactDOMServer.renderToString(element)
将 React 元素渲染为其初始 HTML。React 将返回一个 HTML 字符串。您可以使用此方法在服务器上生成 HTML,并在初始请求时发送标记以加快页面加载速度,并允许搜索引擎出于 SEO 目的抓取您的页面。
如果你调用
ReactDOM.hydrate()
一个已经有这个服务器渲染标记的节点,React 将保留它并且只附加事件处理程序,让你有一个非常高性能的首次加载体验。
如果你想要一个交互式 DOM 结构,你应该使用正常的ReactDOM.render(...)
方法来渲染你的组件。
let placeholder = document.getElementById('placeholder');
ReactDOM.render(<Menu />, placeholder);
// import { BrowserRouter as Router, Link } from 'react-router-dom';
// import { useState } from 'react';
const { BrowserRouter: Router, Link } = ReactRouterDOM;
const { useState } = React;
const Menu = () => {
let [pageNumber, switchPage] = useState(1);
let dish = {
categories: [
'proin blandit',
'suspendisse non',
'fermentum ultrices',
'volutpat vulputat'
],
names: [
['Sed fermentum', 'Sapien nec lobortis', 'Tristique in suspendisse', 'Pellentesque mattis elit', 'Vel interdum velit'],
['Nam nisi quam', 'Donec non viverra', 'Morbi suscipit mattis', 'Sed dignissim nisi', 'Aliquam vitae'],
['Curabitur ante mi', 'Nulla a felis', 'Donec porta convallis ', 'Vestibulum viverra ', 'Nullam viverra '],
['Vestibulum odio', 'Mauris neque ligula', 'Praesent iaculis nunc', 'Cras sollicitudin est', 'Class aptent taciti ']
],
prices: [
[13.99, 11.99, 15.99, 17.99, 21.99],
[22.99, 20.99, 18.99, 16.99, 24.99],
[11.99, 21.99, 31.99, 25.99, 15.99],
[6.99, 8.99, 10.99, 4.99, 8.99]
]
}
let iterator = Math.abs(pageNumber % 4);
let lineBreak = window.innerWidth <= 750 ? <br/> : undefined;
return (
<Router>
<section className='menu'>
<i className='fas fa-chevron-circle-left' id='menu-arrow-left' onClick={() => switchPage(pageNumber - 1)}></i>
<h1 className='dish-category'>You are viewing {dish.categories[iterator]}</h1>
<Link to='/home'><i className='fas fa-times'></i></Link>
<ul className='dish-list'>
<li className='dish'>{dish.names[iterator][0]} {lineBreak} <span className='price'>{dish.prices[iterator][0]} PLN</span></li>
<li className='dish'>{dish.names[iterator][1]} {lineBreak} <span className='price'>{dish.prices[iterator][1]} PLN</span></li>
<li className='dish'>{dish.names[iterator][2]} {lineBreak} <span className='price'>{dish.prices[iterator][2]} PLN</span></li>
<li className='dish'>{dish.names[iterator][3]} {lineBreak} <span className='price'>{dish.prices[iterator][3]} PLN</span></li>
<li className='dish'>{dish.names[iterator][4]} {lineBreak} <span className='price'>{dish.prices[iterator][4]} PLN</span></li>
</ul>
<i className='fas fa-chevron-circle-right' id='menu-arrow-right' onClick={() => switchPage(pageNumber + 1)}></i>
</section>
</Router>
)
}
let placeholder = document.getElementById('placeholder');
ReactDOM.render(<Menu />, placeholder);
<div id="placeholder"></div>
<link crossorigin rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/react-router-dom@5/umd/react-router-dom.js"></script>
推荐阅读
- javascript - 在嵌套数组对象中查找对象键
- c#-3.0 - 如果 DB 中为 Null,如何在视图的文本框中显示空白
- android - Firebase Analytics 上的按钮按下事件
- org-mode - 在组织模式下更改“目录”标题
- javascript - 用另一个 HTML 元素的文本覆盖一个 HTML 元素的 ID
- java - 如何在akkaquartz中创建一个触发器,它只会在特殊时间开始执行一次作业
- html - 将css表格单元格推出浏览器窗口
- objective-c - 如何在 macOS 应用程序目标 c 中将文件压缩为 .xz 格式
- scala - 如何在cassandra表中存储hashmap
- docker - Docker 在 Dockerfile 中执行 cp 或 mv 命令,但更改未显示在图像中