英文:
A strange problem about updating useState
问题
这是我的代码:
const { useState, useEffect } = React;
function App() {
let [count, setCount] = useState(0);
let [num, setNum] = useState(0);
useEffect(() => {
setCount((pre) => {
return pre + 1;
});
setNum(num + 1);
}, []);
return (
<p>
count:{count} num:{num}
</p>
);
}
ReactDOM.createRoot(document.querySelector("#app")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
结果是:count:2 num:1! 为什么?
理论上,num 和 count 应该是同步的,我不知道发生了什么!
在开发模式下,useEffect
的回调被执行了两次。
英文:
Here is my code :
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const {useState, useEffect} = React;
function App() {
let [count, setCount] = useState(0);
let [num, setNum] = useState(0);
useEffect(() => {
setCount((pre) => {
return pre + 1;
});
setNum(num + 1);
}, []);
return (
<p>
count:{count} num:{num}
</p>
);
}
ReactDOM.createRoot(document.querySelector("#app"))
.render(<React.StrictMode><App /></React.StrictMode>);
<!-- language: lang-html -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
<!-- end snippet -->
The result is : count:2 num:1! why?
In theory, num and count should be synchronous, I don't know what happend!<br>
In dev mode, useEffect's callback executed twice.
答案1
得分: 2
这是由于StrictMode的原因:
Strict Mode仅在开发环境中运行,不会妨碍生产构建。它会记录额外的警告或错误,并调用函数两次以确保始终出现预期的结果。
你可能会想为什么它们具有不同的值,以及你认为它们应该是相同的,要么是1,要么是2。
这是因为当你使用类似于count
的函数来更新状态值时:
setCount((pre) => {
return pre + 1;
});
这将使状态更新基于它之前的值,而不是基于它在上一次渲染中的值,这就是为什么我们使用useState
的函数,以便在下一次渲染之前访问状态的先前值,并在组件重新渲染之前再次更新它,就像在这个示例中发生的那样。
因此,在这里,第二次useEffect
运行(因为StrictMode),pre
等于1
,所以最终值将是2
。
然而,当你以这种方式更新你的状态:
setNum(num + 1);
它将基于num
进行更新,而num
仍然等于0,因为组件尚未重新渲染。
英文:
This is because of StricMode :
>Strict Mode only runs in development, which does not impede the production build. It logs extra warnings or errors and invokes functions twice to ensure that the expected results always occur
you may wonder why they have different values and you think that they should have the same, either 1 or 2 <br>
This is because when you update a state value with the function like you did for count
:
setCount((pre) => {
return pre + 1;
});
This will make the state updates based on it previous values not based on its value in the last render <br> and this is why we use the function of useState
so to have access to the previous value of the state before the next render and we can also update it again just before the component rerenders as it happend in this example
So here the second time useEffect runs (because of strictMode) pre
is equal to 1
so the final value will be 2
.<br>
However when you update your state this way :
setNum(num + 1);
It will be updated based on num
and num
is still equal to 0 because the component didn't rerendered yet
答案2
得分: 0
代码部分不需要翻译,以下是翻译好的内容:
这背后的主要原因是StrictMode
StrictMode 会在开发环境中将组件渲染两次(但在生产环境中不会),以便检测代码中的任何问题并提出警告(这可能非常有用)。
如果您想摆脱这一点,请将
ReactDOM.render(
<React.StrictMode>
{app}
</React.StrictMode>,
document.getElementById('root')
);
更改为
ReactDOM.render(
{app}
document.getElementById('root')
);
英文:
The prime reason behind this is StrictMode
> StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them (which can be quite useful).
If you want to get rid of this, change
ReactDOM.render(
<React.StrictMode>
{app}
</React.StrictMode>,
document.getElementById('root')
);
to
ReactDOM.render(
{app}
document.getElementById('root')
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论