React的setState Hook未变更状态时为何触发两次组件渲染?
React 17 相同状态值触发多余渲染原因
这是React 17版本的固有特性,和Strict Mode没有关系,核心差异来自useState的更新 bailout 逻辑:
- 首次页面加载时,会触发一次默认渲染,控制台输出:
Rendering app Rendering man with Blue Shirt - 第一次点击「Change to red shirt」按钮时,状态从
Blue Shirt更新为Red Shirt,属于有效状态变更,触发第二次渲染,控制台输出对应渲染日志。 - 后续两次点击按钮时,传入的新状态和当前
shirt的值完全相等,React 17 会执行一次预防性渲染校验:- 会完整运行一次组件函数体,所以你会看到
console.log语句执行 - 后续diff阶段对比前后渲染结果没有变化,就不会提交更新到DOM,也不会触发
useEffect等生命周期回调 - 这次校验执行后,后续再传入相同的状态值,不会再重复执行组件函数
- 会完整运行一次组件函数体,所以你会看到
React 18已经优化了这个场景:当setState传入和当前完全相等的状态值时,不会再执行组件函数体,也就不会出现多余的日志输出。
你可以通过添加useEffect验证真实更新时机:
useEffect(() => { console.log("Shirt 状态真的发生了变更:", shirt) }, [shirt])
你会发现这个useEffect只会在状态首次加载、第一次点击红按钮时执行,多余的预防性渲染不会触发它。
内容的提问来源于stack exchange,提问作者Nícolas Amarante
相关产品推荐
相关产品推荐

