为何调用useState传入相同状态时组件仍重渲染?如何避免?
为啥React里用useState传相同布尔值,组件有时还会重渲染?咋阻止?
先说说为啥会出现这情况
首先得明确React useState的更新规则:React在处理setState调用时,会用**Object.is()**来对比新旧状态的值。要是两者相等,React就会跳过组件重渲染的流程。
那你碰到的“点false按钮时,哪怕state已经是false了还会重渲染”,最常见的原因有俩:
- 开发环境的StrictMode在搞事情
咱们在React开发模式下,StrictMode会故意让组件的渲染函数跑两次(还有其他钩子/生命周期函数也是),目的是帮咱们揪出代码里可能存在的副作用问题。这时候你看到控制台打印两次rendering..,就会误以为是“没必要的重渲染”,但这只是开发环境的调试操作,到生产环境就不会有这情况了。你可以去看看入口文件(比如index.js),是不是把组件包在<React.StrictMode>标签里了? - 是不是真的传了相同状态?
你的示例代码里是直接传false,布尔值是原始类型,Object.is(false, false)肯定是true,所以这种情况可以排除。但要是你的实际代码更复杂,比如状态是引用类型(对象、数组),那浅比较可能失效,但你的情况显然不是这个问题。
从你的描述来看,十有八九是StrictMode的锅。
怎么阻止真正的不必要重渲染
要是排除了StrictMode,或者生产环境下还是有相同状态重渲染的问题,你可以这么优化:
- 手动判断状态再更新
调用setState之前,先看看新状态和当前状态是不是一样,不一样再更新:
这样就能保证只有状态真的变了,才会触发重渲染。<button onClick={() => { if (state !== false) { setState(false); } }}>false</button> - 函数式更新(适合复杂状态)
要是你的状态是对象、数组这种引用类型,浅比较可能不管用,这时候可以用函数式更新,在函数里做判断:
不过对于布尔这种简单的原始类型,第一种手动判断的方式就够了。setState(prevState => { if (prevState !== false) { return false; } return prevState; // 返回当前状态,不会触发重渲染 });
我试了你的代码,结果是这样的
我跑了你的示例代码,关掉StrictMode的话:
- 第一次渲染:控制台打
rendering.. true - 点
true按钮:当前state已经是true,Object.is(true, true)是true,所以不会重渲染,控制台没新输出 - 点
false按钮:state从true变false,触发重渲染,打rendering.. false - 再点
false按钮:Object.is(false, false)是true,不会重渲染,控制台没新输出
要是开了StrictMode,每次重渲染都会打两次日志,这就容易让人误会“状态没变还重渲染了”,但这真的只是开发环境的调试机制,生产环境就正常了。
内容的提问来源于stack exchange,提问作者oygen
相关产品推荐
相关产品推荐

