Как предотвратить бесполезные запросы на обновление в `useEffect` без использования дополнительных переменных - PullRequest
1 голос
/ 27 октября 2019

Я хочу сделать это

  useEffect(() => {
    if (!datasetsState.list.length) {
      dispatch({ type: DatasetsActionTypes.FETCH, payload: {} });
    }
  }, [datasetsState, dispatch]);

, но dispatch({ type: DatasetsActionTypes.FETCH, payload: {} }); вызывает обновление datasetsState, что приведет к бесконечному циклу, если datasetsState.list останется пустым после ответа

Одно из решениймоя проблема состоит в том, чтобы удалить datasetsState из массива зависимостей, но я получу предупреждение exhaustive-deps, которого я хочу избежать.

И следующий код также будет работать для меня и не вызывает никакихпредупреждения. Но это уродливое и сложное решение для довольно распространенной проблемы, я думаю.

const [isDoneOnce, setIsDoneOnce] = useState(false);
  useEffect(() => {
    if (isDoneOnce) {
      return;
    }
    if (!datasetsState.list.length) {
      dispatch({ type: DatasetsActionTypes.FETCH, payload: {} });
    }
    setIsDoneOnce(true);
  }, [datasetsState, dispatch]);

Как я могу предотвратить обновление useEffect без использования дополнительных переменных, таких как isDoneOnce?

Ответы [ 2 ]

1 голос
/ 27 октября 2019

Убедитесь, что вы зависите от фактического значения, используемого внутри useEffect, например:

const len = datasetsState.list.length

useEffect(() => {
  if (!len) {
    dispatch(...)
  }
}, [len, dispatch])
1 голос
/ 27 октября 2019

Вы должны использовать «глобальную» переменную или ссылку.

Выбор зависит от контекста, отметьте этот ответ о различиях.

TL; DR - зависит от контекста «запустить один раз» , срок службы приложения или срок службы компонента .

Ссылка:

const App = () => {
  const isDoneRef = useRef(false);

  useEffect(() => {
    if (!isDoneRef.current) {
      dispatch({ type: DatasetsActionTypes.FETCH, payload: {} });
      isDoneRef.current = true;
    }
  }, [dispatch]);

  return <></>;
};

Переменная:

let isDoneGlobal = false;

const App = () => {
  useEffect(() => {
    if (!isDoneGlobal) {
      dispatch({ type: DatasetsActionTypes.FETCH, payload: {} });
      isDoneGlobal = true;
    }
  }, [dispatch]);

  return <></>;
};
...