Как исправить предупреждение об отсутствующей зависимости при использовании useEffect React Hook?

С React 16.8.6 (это было хорошо в предыдущей версии 16.8.3), я получаю эту ошибку, когда пытаюсь предотвратить бесконечный цикл при запросе выборки

./src/components/BusinessesList.js
Line 51:  React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array  react-hooks/exhaustive-deps

Мне не удалось найти решение, которое останавливает бесконечный цикл. Я хочу держаться подальше от использования useReducer(). Я нашел это обсуждение https://github.com/facebook/react/issues/14920, где возможное решение - You can always // eslint-disable-next-line react-hooks/exhaustive-deps if you think you know what you're doing. Я не уверен в том, что я делаю, поэтому я еще не пытался его реализовать.

У меня есть текущая настройка React-хук useEffect работает постоянно навсегда/бесконечный цикл, и единственный комментарий касается useCallback(), с которым я не знаком.

Как я в настоящее время использую useEffect() (который я хочу запустить только один раз в начале, аналогично componentDidMount())

useEffect(() => {
    fetchBusinesses();
  }, []);
const fetchBusinesses = () => {
    return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };

Ответ 1

Если вы не используете метод fetchBususiness где-либо кроме эффекта, вы можете просто переместить его в эффект и избежать предупреждения

useEffect(() => {
    const fetchBusinesses = () => {
       return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };
  fetchBusinesses();
}, []);

Однако, если вы используете fetchBususiness за пределами рендера, вы должны отметить две вещи

  1. Если есть какая-либо проблема, если вы не передаете fetchBusinesses как метод и что он используется во время монтирования с закрывающим закрытием, проблем не будет.
  2. Зависит ли ваш метод от каких-то переменных, которые он получает из закрытого замыкания, что не так для вас.
  3. При каждом рендеринге fetchBususiness будет воссоздан, и, следовательно, передача его в useEffect вызовет проблемы. Итак, сначала вы должны запомнить fetchBususiness, если вы должны были передать его в массив зависимостей.

Подводя итог, я бы сказал, что если вы используете fetchBusinesses за пределами useEffect вы можете отключить правило, используя //eslint-disable-next-line react-hooks/exhaustive-deps противном случае вы можете переместить метод внутри useEffect.

Чтобы отключить правило, вы должны написать его так

useEffect(() => {
   // other code
   ...

   // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) 

Ответ 2

./src/components/BusinessesList.js
Line 51:  React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array  react-hooks/exhaustive-deps

Это не ошибка JS/React, а предупреждение eslint (eslint-plugin -act-hooks).

Он говорит вам, что ловушка зависит от функции fetchBusinesses, поэтому вы должны передать ее как зависимость.

useEffect(() => {
  fetchBusinesses();
}, [fetchBusinesses]);

Это может привести к вызову функции при каждом отображении, если функция объявлена в компоненте, например:

const Component = () => {
  /*...*/

  //new function declaration every render
  const fetchBusinesses = () => {
    fetch('/api/businesses/')
      .then(...)
  }

  useEffect(() => {
    fetchBusinesses();
  }, [fetchBusinesses]);

  /*...*/
}

потому что каждый раз функция повторно объявляется с новой ссылкой

Правильный способ сделать это:

const Component = () => {
  /*...*/

  // keep function reference
  const fetchBusinesses = useCallback(() => {
    fetch('/api/businesses/')
      .then(...)
  }, [/* additional dependencies */]) 

  useEffect(() => {
    fetchBusinesses();
  }, [fetchBusinesses]);

  /*...*/
}

Подробнее: https://github.com/facebook/react/issues/14920

Ответ 3

Эта статья является хорошим учебником по извлечению данных с помощью хуков: https://www.robinwieruch.de/react-hooks-fetch-data/

По сути, useEffect определение функции извлечения в useEffect:

useEffect(() => {
  const fetchBusinesses = () => {
    return fetch("theUrl"...
      // ...your fetch implementation
    );
  }

  fetchBusinesses();
}, []);

Ответ 4

Решение также дается useCallback, они советуют вам использовать useCallback который возвратит версию вашей функции в виде useCallback:

Функция "fetchBususiness" изменяет зависимости useEffect Hook (в строке NN) при каждом рендеринге. Чтобы исправить это, оберните определение 'fetchBususiness' в его собственный useCallback() Hook response-hooks/исчерпывающий-deps

useCallback прост в использовании, так как имеет ту же сигнатуру, что и useEffect разница в том, что useCallback возвращает функцию. Это будет выглядеть так:

 const fetchBusinesses = useCallback( () => {
        return fetch("theURL", {method: "GET"}
    )
    .then(// some stuff)
    .catch(// some error handling)
  }, [//deps])
  // We have a first effect thant uses fetchBusinesses
  useEffect(() => {
    // do things and then fetchBusinesses
    fetchBusinesses(); 
  }, [fetchBusinesses]);
   // We can have many effect thant uses fetchBusinesses
  useEffect(() => {
    // do other things and then fetchBusinesses
    fetchBusinesses();
  }, [fetchBusinesses]);

Ответ 5

Вы можете удалить второй тип аргумента array [] но fetchBusinesses() также будет вызываться при каждом обновлении. Вы можете добавить оператор IF в реализацию fetchBusinesses() если хотите.

React.useEffect(() => {
  fetchBusinesses();
});

Другой fetchBusinesses() - реализовать fetchBusinesses() вне вашего компонента. Только не забудьте передать любые аргументы зависимости в ваш fetchBusinesses(dependency), если таковые имеются.

function fetchBusinesses (fetch) {
  return fetch("theURL", { method: "GET" })
    .then(res => normalizeResponseErrors(res))
    .then(res => res.json())
    .then(rcvdBusinesses => {
      // some stuff
    })
    .catch(err => {
      // some error handling
    });
}

function YourComponent (props) {
  const { fetch } = props;

  React.useEffect(() => {
    fetchBusinesses(fetch);
  }, [fetch]);

  // ...
}

Ответ 6

Может быть

useEffect(fetchBusiness,[])

Ответ 7

просто отключите eslint для следующей строки;

useEffect(() => {
   fetchBusinesses();
// eslint-disable-next-line
}, [fetchBusinesses]);