You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 15:15:34