useEffect и массив зависимостей - PullRequest
1 голос
/ 26 апреля 2020

Я пытаюсь понять, как реагирует useEffect работает с объектами.

Вот пример, который поможет продемонстрировать мой вопрос:

export function UseEffectHook() {
  const initialState = {
    firstName: "Joe",
    lastName: "Smith",
    address: {
      home: "123 street"
    }
  };
  const [user, setUser] = useState(initialState);
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("triggered");
  }, [user]);

  return (
    <div>
      <p>useEffect - Practice with different deps</p>
      {JSON.stringify(user)}
      <label>Firstname:</label>

      <input
        type="text"
        onChange={e => setUser({ ...user, firstName: e.target.value })}
      />
      <br />
      <label>Lastname:</label>
      <input
        type="text"
        onChange={e => setUser({ ...user, lastName: e.target.value })}
      />
      <button onClick={() => setCount(count + 1)}>Button</button>
   </div>
  );
}

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

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

Я не могу найти достаточно надуманный пример, чтобы помочь продемонстрировать, когда и почему useEffect перезапускается с использованием объектов. Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 26 апреля 2020

useEffect будет повторно запускаться с объектом в его массиве зависимостей всякий раз, когда этот объект изменяет ссылки.

Например, в вашем коде пользователь всегда стабилен, пока вы не вызовете setUser, в этом случае он изменится на новый ссылаться и запускаться в этой точке.

Если вместо этого вы определили пользователя как новый объект в каждом рендере, то вместо этого useEffect будет запускаться каждый раз при повторном рендеринге компонента.

  const user = {
    firstName: 'Joe',
    lastName: 'Smith',
    address: {
      home: '123 street',
    },
  };

Это все о ссылочном равенстве. Будь предыдущий пользователь === newUser на каждом рендере. React по существу выполняет проверку, очень похожую на эту (я считаю Object.is) для каждой переменной в массиве зависимостей.

1 голос
/ 26 апреля 2020

Запишите свой компонент.

Изменения:

  • Переместите initialState за пределы UseEffectHook. Вам не нужно создавать initialState каждый повторный рендеринг;
  • use useCallback вернет запомненную версию обратного вызова, которая изменяется только в случае изменения одной из зависимостей;
  • setUser и setCount с функцией обновления ;
  • handleOnChangeUser, которую можно использовать для всех полей пользовательского объекта. Каждый раз handleOnChangeUser - создает новую ссылку на объект пользователя. в этом случае используйтеEffect, способный обнаруживать изменения;

import React, { useCallback, useEffect, useState } from 'react';

const initialState = {
  firstName: "Joe",
  lastName: "Smith",
  address: {
    home: "123 street",
  }
};

export function UseEffectHook() {
  const [user, setUser] = useState(initialState);
  const [count, setCount] = useState(0);
  const handleOnChangeUser = useCallback((event) => {
    const { name, value } = event;
    
    setUser(prevState => ({ ...prevState, [name]: value }));
  }, []);
  
  const increaseCount = useCallback(() => {
    setCount(prevState => prevState + 1);
  }, []);

  useEffect(() => {
    console.log("triggered");
  }, [user]);

  return (
    <div>
      <p>useEffect - Practice with different deps</p>
      {JSON.stringify(user)}

      <label>
        <span>Firstname:</span>

        <input
          type="text"
          name="firstName"
          onChange={handleOnChangeUser}
        />
      </label>
      
      <br />
      
      <label>
        <span>Lastname:</span>
        
        <input
          type="text"
          name="lastName"
          onChange={handleOnChangeUser}
        />
      </label>

      <button onClick={increaseCount}>Increase</button>
   </div>
  );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...