问题
在编写 React 代码时,如果你希望多次更新状态,可能会尝试使用 handleClickWrong
中的方式。然而,你会发现实际效果并不如预期:count
只增加了 1,而不是 3。
const root = document.getElementById('root');
const App = () => {
return (
Hello World
);
};
const Counter = () => {
const [count, setCount] = React.useState(0);
const handleClickWrong = () => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
};
return (
{count}
);
};
const rootElement = ReactDOM.createRoot(root);
rootElement.render( );
为什么会出现这种情况呢?要弄清楚这个问题,我们需要了解 React 如何处理状态更新的细节。
React 内部状态更新机制
React 使用了一个内部机制来处理状态更新。我们可以通过以下源码片段了解这背后的实现:
// React 源码中的基本状态处理器
function basicStateReducer(state, action) {
// $FlowFixMe: Flow doesn't like mixed types
return typeof action === 'function' ? action(state) : action;
}
在我们使用 handleClickWrong
的情况下,React 会按照以下方式处理状态更新:
// 假设初始状态为 0,我们传递的值是 1
newState = basicStateReducer(0, 1);
由于 basicStateReducer
接收到的 action
不是函数,它会直接返回这个值作为最新状态。因此,newState
会被更新为 1。
回到 handleClickWrong
的例子:
const handleClickWrong = () => {
setCount(count + 1); // = basicStateReducer(0, 1) => 1
setCount(count + 1); // = basicStateReducer(0, 1) => 1
setCount(count + 1); // = basicStateReducer(0, 1) => 1
};
由于 count
在当前 Counter
函数的作用域内,三次 setCount
调用的值都是 count + 1
。因此,即使调用了多次 setCount
,由于 React 只处理了最新的 count
值,结果每次都将状态更新为 1。最终渲染时,count
依然只有 1。
解决方案
了解了原因后,我们可以改用函数形式的更新来解决这个问题。注意到 basicStateReducer
会检查传入的 action
,如果是函数,React 会用当前内部存储的状态作为参数传给这个函数。这样,我们可以基于最新的状态进行更新。
const handleClick = () => {
setCount((prevCount) => prevCount + 1); // = basicStateReducer(0, (prevCount) => prevCount + 1) => 0 + 1 => 1
setCount((prevCount) => prevCount + 1); // = basicStateReducer(1, (prevCount) => prevCount + 1) => 1 + 1 => 2
setCount((prevCount) => prevCount + 1); // = basicStateReducer(2, (prevCount) => prevCount + 1) => 2 + 1 => 3
};
通过使用函数形式的更新,我们可以确保每次状态更新都基于前一个状态,从而实现预期的结果。
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容