Добавление исчерпывающих зависимостей в useEffect и useCallback вызывает бесконечный цикл - PullRequest
3 голосов
/ 23 мая 2019

Итак, я подумал, что я освоился с этими крючками, но правило пуха react-hooks/exhaustive-deps сбивает меня с толку.

У меня есть этот метод внутри моего провайдера

const onScreenChange = useCallback(
(key, value) => {
  const newState = Object.assign({}, screenState, { [key]: value });
  localStorage.setItem('screens', JSON.stringify(newState));
  setScreenState(newState);
},
[]); // screenState

Я разрешаю остальной части моего приложения получить доступ к этому, передав его в значение prop ...

return <Provider value={{onScreenChange, ... }}>children</Provider>

А затем я вызываю этот метод из дочернего компонента при изменении маршрута

useEffect(() => {
   if (match.path === `/${screenKey}`) {
     onScreenChange(screenKey, 'external');
   }
}, [onScreenChange, match.path, screenKey]);

Приведенный выше код работает именно так, как я хочу, и я не вижу, чтобы это вызывало какие-либо ошибки. Однако Эслинт говорит мне:

React Hook useCallback has a missing dependency: 'screenState'. Either include it or remove the dependency array

Когда я добавляю screenState в массив, он вызывает бесконечный цикл, как только вызывается метод onScreenChange.

Совершенно очевидно, почему сейчас происходит цикл, но как мне остановить это и "следовать правилам"?

Заранее спасибо за любую помощь!

1 Ответ

2 голосов
/ 23 мая 2019

Предупреждение от eslint кажется правильным. Поскольку значение screenState не будет корректно обновляться, если метод onScreenChange вызывается несколько раз. Вы должны предоставить screenState в качестве зависимости от useCallback

const onScreenChange = useCallback(
(key, value) => {
  const newState = Object.assign({}, screenState, { [key]: value });
  localStorage.setItem('screens', JSON.stringify(newState));
  setScreenState(newState);
},
[screenState]); 

Другой способ написать тот же код без добавления deps - использовать шаблон обратного вызова средства обновления состояний

const onScreenChange = useCallback(
(key, value) => {


  setScreenState(oldState => {
       const newState = Object.assign({}, oldState, { [key]: value });
       localStorage.setItem('screens', JSON.stringify(newState));
       return newState;
  });
},
[]); 

Однако вы можете отключить предупреждение deps, если вы абсолютно уверены, что вы пытаетесь сделать правильно.

Вы можете прочитать ниже сообщение для получения дополнительной информации:

Как исправить отсутствующую зависимость в React Hook useEffect

...