Что заставляет этот компонент обнаруживать изменения в его опорах? - PullRequest
3 голосов
/ 24 февраля 2020

В следующем минимальном примере родительский компонент имеет свойство data и передает data.value дочернему элементу. Я изо всех сил пытаюсь понять, что именно здесь происходит со стратегией обновления:

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} />
    </>
  );
}

(См. Это Codesandbox ) Теперь, когда кнопка нажата, я думаю, что происходит следующее:

  • Приложение handleButtonClick() выполняется, и состояние data теперь ссылается на новый объект. Поэтому первый useEffect (проверяющий на data) приложения вызывает.

  • Однако data.value все еще содержит ту же ссылку (на MY_DATAVALUE), поэтому второй useEffect приложения (поэтому проверка на data.value) не срабатывает.

НО: ребенок запускает useEffect (проверка на props). Это почему? По словам родителя, data.value НЕ изменилось (в противном случае сработал бы второй useEffect).

Можете ли вы объяснить мне, почему срабатывает Childs useEffect? Как я могу узнать, действительно ли изменились реквизиты? Должен ли я индивидуально проверять все проп-ключи? Спасибо!

1 Ответ

1 голос
/ 24 февраля 2020

useEffect зависимости приведут к изменению, если то, что мы предоставляем, отличается. Это происходит, если мы передаем одну и ту же ссылку с другим значением или если мы передаем другую ссылку.

const newData = {
  value: MY_DATAVALUE
};

setData(newData);

data теперь ссылается на другой объект, тогда как клавиша value ссылается на то же, что и предыдущее значение.

Это означает, что этот хук сработает:

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

Пока это не сработает:

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

Пока это то, что Вы объяснили в обоих пунктах.

В случае дочернего объекта, объект props является новой ссылкой на каждый рендер.

По этой причине этот хук всегда будет срабатывать:

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

Пока этот хук не будет срабатывать:

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

// In Parent...

<Child value={MY_DATAVALUE} />

// In Child...

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