0

I have two children Components, when I onChange in first children, then the second children re render, I don't want to the second children re render. Online code example: https://codesandbox.io/s/billowing-glitter-r5gnh3?file=/src/App.js:1287-1297

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.InputNumber);
  console.log("====ChildInput2===");
  return (
    <InputNumber
      value={value}
      onChange={(v) => {
        setValue(v.target.value);
        onChangeValue("age", v.target.value);
      }}
    />
  );
};

when I onChange in ChildInput1, then ChildInput2 re-render, I don't want to the ChildInput2 re-render. Example image

enter image description here

Vy Do
  • 46,709
  • 59
  • 215
  • 313
sanheart
  • 59
  • 5
  • 1
    Here you are updating the `context` value and not internal state of the component, so re render happens in both of the child components. – Maniraj Murugan Aug 23 '22 at 10:25

2 Answers2

1

As Andrey explained, you should fix the following line:

//you have
const [value, setValue] = React.useState(initValue.InputNumber);
// should be
const [value, setValue] = React.useState(initValue.age);

Additionally, initValue gets unnecessarily re-computed on every re-render, so it should be outside the scope of Parent:

const initValue = {
    name: "zhang",
    age: 3
  };

const Parent = () => {...}

Regarding re renderings, it is ok. When a Provider gets the value changed, all their childs wrapped in a consumer rerender. This is natural. This post explains why.

A component calling useContext will always re-render when the context value changes. If re-rendering the component is expensive, you can optimize it by using memoization.

In this case, it is not expensive enough to consider memoization.

I Hope it helps

Jonatan Kruszewski
  • 1,027
  • 3
  • 23
0

You have a typo in your code:

//you have
const [value, setValue] = React.useState(initValue.InputNumber);
// should be
const [value, setValue] = React.useState(initValue.age);

also update like that

<InputNumber
  value={value}
  onChange={(value) => {
      setValue(value);
      onChangeValue("age", value);
  }}
/>

and when you fix like that do not worry about re-render as state of ChildInput2 will no be changed

Andrey Smolko
  • 712
  • 3
  • 8