为什么React中父组件Context更新会重渲染未使用该Context的子组件
结论
父组件的任意Context变更不会强制重渲染所有子组件,你遇到的RefForwarder重渲染是TestApp自身状态变更触发的默认重渲染行为,和Context没有直接关联。
原因解释
React的默认重渲染规则是:只要组件自身的状态发生变更,该组件及其所有后代子组件都会触发重渲染,和子组件是否接收props、是否消费Context无关。
你点击按钮调用themeSetter时,修改的是TestApp内部的useContextSelectedTheme状态,直接触发了TestApp的重渲染,作为TestApp子组件的RefForwarder自然会跟着走默认重渲染流程。
验证方法
你可以用React.memo包裹RefForwarder组件:
const RefForwarder = React.memo(() => { // 原有组件逻辑 })
如果修改后RefForwarder不再无意义重渲染,就可以确认重渲染的根源是TestApp的全局重渲染,而非Context变更的影响。
Context触发重渲染的规则
只有明确消费了对应Context的组件,才会在该Context的value发生引用变化时触发重渲染。你场景中的RefForwarder没有消费HookContext,完全不会被HookContext的变更直接影响。
额外优化提示
你当前HookContext.Provider传递的value是每次渲染都重新生成的字面量对象:
// 每次TestApp渲染都会生成新的对象引用 value={{ selectedTheme: useContextSelectedTheme, themeSetter: useContextThemeSetter }}
哪怕useContextSelectedTheme没有变化,只要TestApp因为其他状态变更重渲染,这个value的引用就会更新,导致所有消费HookContext的组件触发不必要的重渲染。可以用useMemo缓存value解决这个问题:
const hookContextValue = React.useMemo(() => ({ selectedTheme: useContextSelectedTheme, themeSetter: useContextThemeSetter }), [useContextSelectedTheme, useContextThemeSetter]) // Provider传入缓存后的值 <HookContext.Provider value={hookContextValue}>
内容的提问来源于stack exchange,提问作者MamorukunBE

