React useContext场景下,如何避免无关子组件不必要重渲染
解决React子组件不必要重渲染问题
问题描述
我有两个子组件ChildInput1与ChildInput2,操作ChildInput1触发onChange事件时,ChildInput2会出现不必要的重渲染(控制台打印====ChildInput2===日志),需要优化避免这种情况。
相关代码如下:
const EditSceneModalStore = React.createContext(undefined); const Parent = () => { const [saveValue, setSaveValue] = React.useState({}); const initValue = { name: "zhang", age: 3 }; const onSave = () => { console.log("===saveValue==", saveValue); }; const onChangeValue = (key, value) => { const newValue = { ...saveValue, [key]: value }; setSaveValue(newValue); }; return ( <EditSceneModalStore.Provider value={{ initValue, onChangeValue }} > <ChildInput1 /> <ChildInput2 /> <Button onClick={onSave} type="primary"> save </Button> </EditSceneModalStore.Provider> ); }; const ChildInput1 = () => { const { onChangeValue, initValue } = React.useContext(EditSceneModalStore); const [value, setValue] = React.useState(initValue.name); return ( <Input value={value} onChange={(v) => { setValue(v.target.value); onChangeValue("name", v.target.value); }} /> ); }; const ChildInput2 = () => { const { initValue, onChangeValue } = React.useContext(EditSceneModalStore); const [value, setValue] = React.useState(initValue.age); console.log("====ChildInput2==="); return ( <InputNumber value={value} onChange={(v) => { setValue(v); onChangeValue("age", v); }} /> ); };
问题根源
每次Parent组件调用setSaveValue更新状态时,onChangeValue函数会被重新创建,导致EditSceneModalStore.Provider的value对象引用发生变化。所有消费该Context的子组件(包括ChildInput2)会因为Context值变化触发重渲染,即使组件本身的业务逻辑没有依赖变化的内容。
解决方案
1. 用useCallback缓存事件处理函数
通过React.useCallback缓存onChangeValue函数,避免每次渲染时重新创建函数实例;同时使用函数式更新获取最新状态,减少依赖项:
const Parent = () => { const [saveValue, setSaveValue] = React.useState({}); const initValue = { name: "zhang", age: 3 }; const onSave = () => { console.log("===saveValue==", saveValue); }; // 缓存函数,依赖项为空数组 const onChangeValue = React.useCallback((key, value) => { setSaveValue(prevState => ({ ...prevState, [key]: value })); }, []); return ( <EditSceneModalStore.Provider value={{ initValue, onChangeValue }} > <ChildInput1 /> <ChildInput2 /> <Button onClick={onSave} type="primary"> save </Button> </EditSceneModalStore.Provider> ); };
2. 用memo包裹子组件
结合React.memo包裹子组件,只有当组件依赖的props或Context值真正变化时,才会触发重渲染:
const ChildInput2 = React.memo(() => { const { initValue, onChangeValue } = React.useContext(EditSceneModalStore); const [value, setValue] = React.useState(initValue.age); console.log("====ChildInput2==="); return ( <InputNumber value={value} onChange={(v) => { setValue(v); onChangeValue("age", v); }} /> ); });
额外优化:拆分Context(可选)
如果组件间依赖差异较大,可将Context拆分为多个独立实例(比如将initValue和onChangeValue分开),减少无关组件的重渲染触发范围。不过当前场景下,前两个方案已足够解决问题。
内容的提问来源于stack exchange,提问作者sanheart
相关产品推荐
相关产品推荐

