What causes this component to detect changes in its props?

Raphael :

In the following minimal example, a parent component has a data property and passes data.value to a child. I am struggling to understand what exactly is going on here with the update strategy:

const MY_DATAVALUE = {
  a: 1,
  b: 2
};

const DATA = {
  value: MY_DATAVALUE
};

function Child(props) {
  useEffect(() => {
    console.log("child props changed");
  }, [props]);

  return <h1>Child</h1>;
}

export default function App() {
  const [data, setData] = useState(DATA);

  useEffect(() => {
    console.log("data changed");
  }, [data]);

  useEffect(() => {
    console.log("data.value changed");
  }, [data.value]);

  function handleButtonClick() {
    const newData = {
      value: MY_DATAVALUE
    };
    setData(newData);
  }

  return (
    <>
      <button onClick={handleButtonClick}>Button</button>
      <Child value={data.value} />
    </>
  );
}

(See this Codesandbox) Now, when the button is clicked, I think the following happens:

  • App's handleButtonClick() is executed and the data-state now refers to a new object. Therefore App's first useEffect (checking for data) triggers.

  • However data.value still contains the same reference (to MY_DATAVALUE), therefore App's second useEffect (checking for data.value) does not trigger.

BUT: The Child's useEffect (checking for props) triggers. Why is that? According to the parent, data.value did NOT change (Otherwise the second useEffect would have triggered).

Can you explain to me, why the Childs useEffect triggers`? How could I find out if the props "really" changed? Would I have to individually check for all prop-keys? Thank you!

Alvaro :

useEffect dependencies will trigger a change if what we provide is different. This happens if we pass the same reference with a different value or if we pass a different reference.

const newData = {
  value: MY_DATAVALUE
};

setData(newData);

data now refers to a different object, while the value key refers to the same as the previous value.

This means, this hook will trigger:

useEffect(() => {
  console.log("data changed");
}, [data]);

While this will not trigger:

useEffect(() => {
  console.log("data.value changed");
}, [data.value]);

So far this is what you explained in both points.

In the case of the child, the props object is a new reference on every render.

For this reason, this hook will always trigger:

useEffect(() => {
  console.log("child props changed");
}, [props]);

While this hook would not trigger:

const MY_DATAVALUE = {
  a: 1,
  b: 2
};

// In Parent...

<Child value={MY_DATAVALUE} />

// In Child...

useEffect(() => {
  console.log("child value changed");
}, [props.value]);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=12386&siteId=1