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

avatar
russ
25 апреля 2019 в 00:35
674435
20
620

В 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(). Я нашел это обсуждение [ESLint] Отзыв о правиле lint 'exhaustive-deps' #14920, где возможное решение You can always // eslint-disable-next-line react-hooks/exhaustive-deps if you think you know what you're doing. Я не уверен в том, что делаю , поэтому я еще не пробовал его реализовывать.

У меня есть эта текущая настройка, React hook 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
      });
  };

Источник
chetan
28 февраля 2021 в 12:05
9

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

Eric Burel
24 ноября 2021 в 12:59
1

И запрос функции, чтобы React улучшили useEffect API, чтобы избежать этой проблемы, четко отделив триггеры эффектов от зависимостей эффектов: предупреждение должно появляться миллион раз в день во всем мире, это должно как-то прекратиться.

Kokodoko
8 декабря 2021 в 16:50
1

Согласитесь, это совершенно неясно из официальной документации. Такая библиотека, как React, не нуждается в форумах и сообщениях в блогах, чтобы заставить ее работать.

Ответы (20)

avatar
Shubham Khatri
25 апреля 2019 в 17:40
547

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

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();
}, []);

Если вы используете fetchBusinesses вне рендеринга, вы должны учитывать две вещи

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

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

Чтобы отключить правило, напишите его так:

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

   // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) 
russ
25 апреля 2019 в 22:39
64

Я использовал решение, которое вы хорошо изложили. Другое решение, которое я использовал в другом месте из-за другой настройки, было useCallback(). Так, например: const fetchBusinesses= useCallback(() => { ... }, [...]) и useEffect() будут выглядеть так: useEffect(() => { fetchBusinesses(); }, [fetchBusinesses]);

Shubham Khatri
26 апреля 2019 в 05:41
6

@russ, вы правы, вам нужно будет запомнить fetchBusiness с помощью useCallback, если вы хотите передать его в массив зависимостей

user210757
18 июня 2019 в 21:30
0

Было бы неплохо, если бы вы показали, куда поставить оператор eslint-disable. Я думал, что это будет выше useEffect

Olivier Boissé
27 октября 2019 в 11:59
34

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

Tapas Adhikary
20 ноября 2019 в 05:08
0

Как насчет асинхронной функции?

Shubham Khatri
20 ноября 2019 в 05:10
0

@TapasAdhikary, асинхронную функцию также можно вызвать из useEffect

Tapas Adhikary
20 ноября 2019 в 05:18
0

Спасибо @ShubhamKhatri, я понял. Мой вопрос заключался в том, что если мы хотим использовать само определение функции внутри useEffect(), а моя функция является ансинхронной функцией, которая была вне useEffect(), как получить это внутри? Функция aync получила ключевое слово await, которое, я полагаю, не может быть размещено как есть.

Shubham Khatri
20 ноября 2019 в 05:19
3

@TapasAdhikary, да, у вас может быть асинхронная функция в useEffect, вам просто нужно написать ее по-другому. Пожалуйста, проверьте coderhelper.com/questions/53332321/…

Giorgi Moniava
23 декабря 2019 в 10:07
0

«Если есть какие-либо проблемы, если вы не передадите fetchBusinesses как метод и что он используется во время монтирования с его закрывающим закрытием, не будет никаких проблем». -> Это предложение неясно.

Fiddle Freak
19 августа 2020 в 13:52
0

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

Akhila
11 октября 2020 в 20:55
0

Но это не работает, когда мы используем async и await внутри функции useEffect. Поэтому я попытался поставить его снаружи. Но это все еще не работает!

Erez Cohen
2 ноября 2020 в 10:09
0

Я думаю, что принятым ответом должен быть ответ на «r g» ниже. ИМО - плохая практика комментировать ошибки ворса, когда есть другое жизнеспособное решение. + вам нужно доверять следующему разработчику, который редактирует этот код, чтобы сначала удалить комментарий.

Robert Moskal
16 ноября 2020 в 15:17
0

Я ненавижу это, когда приходится перемещать функцию внутри хука. Должен быть лучший способ.

rayaqin
9 апреля 2021 в 14:01
9

линтер по-прежнему глуп сегодня, и если вы хотите поведение, подобное componentDidMount, при использовании внешних переменных (необходимо, чтобы некоторые, но не все из них вызывали повторную визуализацию в случае их изменения), вы получите это предупреждение независимо от того, что вы делаете.... в по крайней мере, я не смог найти решение в Интернете

Shubham Khatri
9 апреля 2021 в 16:03
0

@rayaqin Do может отключить линтер для этой строки, если вы абсолютно уверены, что делаете правильно.

rayaqin
11 апреля 2021 в 08:03
0

это не заставит предупреждение браузера исчезнуть, только предупреждение в IDE

Eric Burel
19 августа 2021 в 08:42
0

Привет, ребята, я отправил запрос функции для дополнительного параметра «триггеры» в useEffect, чтобы различать зависимости, которые должны запускать повторный запуск эффекта, и зависимости, которые просто запускают обновление обратного вызова эффекта, но не запускают его. Я хотел бы получить отзыв об этом: github.com/facebook/react/issues/22132 (связанная песочница кода: codesandbox.io/s/fancy-sea-zj5e4 ).

Chev
1 октября 2021 в 16:22
0

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

avatar
Daniel
5 мая 2022 в 17:18
0

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

В eslint встроено правило, которое требует, чтобы вы ссылались на любое другое свойство или часть состояния внутри массива зависимостей useEffect. Это массив, который управляет выполнением useEffect. Это правило хочет видеть его в списке внутри этого массива, который решает, когда повторно запустить функцию useEffect.

Поэтому вам нужно добавить [fetchBusinesses] и предупреждение должно исчезнуть.

Теперь, почему это правило требует, чтобы мы поместили это туда?

Есть некоторые сценарии, в которых использование <65345555522264> и неправильное перечисление всех частей состояния и свойств внутри массива может привести к странным и трудным для отладки проблемам.

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

Теперь произвольное добавление к этому массиву также может привести к ошибкам. Так что в любом случае вы сталкиваетесь с ошибками, которые вы должны решить. В соответствии с вашими комментариями, которые, казалось, решили эту проблему для вас, но я хотел бы продолжить расследование, чтобы узнать, получили ли вы случайно второй запрос GET на вкладке Сеть в Chrome после добавления в fetchBusinesses в ваш массив useEffect.

avatar
Vignesh
5 декабря 2021 в 13:55
0

используя UseEffect fetchBusinesses вызов функции, объявить в useEffect(), объявив константную переменную после вызова имени функции,

useEffect(()=>{
const fetchBusinesses=()=>{
   console.log(useeffect fetchbussinesses functions)
}
 fetchBusinesses();
},[declare the variable used in useeffect hooks ])
avatar
Eran Or
28 октября 2021 в 09:23
1

Это не ответ, специфичный для варианта использования вопроса, а более общий случай, и он охватывает случай, когда использованиеEffect или извлечение и импорт не работает. Сценарий useRef:

Иногда сценарий заключается в том, что useEffect должен иметь пустой массив, и вы по-прежнему хотите использовать его внутри частей состояния useEffect, но все же не хотите внедрять их в качестве зависимостей, также вы можете попробовать использовать useCallback, и теперь реакция жалуется про зависимости useCallback и ты застрял. При этом в некоторых случаях можно использовать useRef. например:

const locationRef = useRef(location);
useEffect(()=>{
const qs = locationRef.current.search
...
},[])

Вы должны быть осторожны при использовании этой техники и помнить, что useRef не активирует процесс рендеринга.

avatar
Narek Ghazaryan
25 сентября 2021 в 08:26
1

Кажется, функция fetchBusinesses объявлена ​​в компоненте. Это означает, что в каждом рендере объявляется новая функция, которая запускает хук.

Есть 2 подхода к устранению проблемы.

  1. Переместите объявление функции fetchBusinesses из компонента.

  2. Оберните функцию fetchBusinesses хуком useCallback.

Первый вариант предпочтительнее.

avatar
Muhammad Farhan
21 сентября 2021 в 13:29
1

Вы можете избавиться от этого предупреждения Es-lint, передав ссылку на него:

Пример указан ниже, однако вы можете посмотреть решение по этой ссылке: https://www.youtube.com/watch?v=r4A46oBIwZk&t=8s

Предупреждение: Строка 13:8: React Hook В React.useEffect отсутствуют зависимости: «история» и «currentUser?.role». Либо включите их, либо удалите массив зависимостей react-hooks/exhaustive-deps

React.useEffect(() => {
    if (currentUser?.role !== "Student") {
        return history.push("/")
    }
}, [])

Разрешение: Шаг 1. Переместите бизнес-логику в отдельную константу

.

Теперь предупреждение: React Hook React.useEffect имеет недостающую зависимость: 'roleChecking'.

const roleChecking = () =>{
   if (currentUser?.role !== "Student") {
        return history.push("/")
    }
}

React.useEffect(() => {
    roleChecking()
}, [])

Последний шаг — создать ссылку на функцию:

  const roleRef = React.useRef();

  const roleChecking = () => {
    if (currentUser?.role !== "Student") {
      return history.push("/");
    }
  };
  roleRef.current = roleChecking;

  React.useEffect(() => {
   return roleRef.current();
  }, [currentUser?.role]);
avatar
Jasurbek Nabijonov
9 апреля 2021 в 07:19
2

В моем случае это предупреждение было связано с моей локальной переменной organization, и когда я поместил organization в массив зависимостей, useEffect будет выполняться бесконечно. Поэтому, если у вас есть проблемы, подобные моей, используйте useEffect с массивом зависимостей и разделите:

Потому что если у вас есть несколько вызовов API, которые изменяют состояние, он вызывает useEffect несколько раз.

От:

  const { organization } = useSelector(withOrganization)
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(getOrganization({}))
    dispatch(getSettings({}))
    dispatch(getMembers({}))
  }, [dispatch, organization])

Кому:

  const { organization } = useSelector(withOrganization)
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(getOrganization({}))
    dispatch(getSettings({}))
  }, [dispatch, organization])

  useEffect(() => {
    dispatch(getMembers({}))
  }, [dispatch])
avatar
Yilmaz
28 марта 2021 в 23:32
1

Это предупреждение возникает, если переменные, которые вы используете внутри useEffect, определены внутри компонента или переданы компоненту в качестве реквизита. Поскольку вы определили fetchBusinesses() внутри того же компонента, вы должны передать его в массив зависимостей.

Но если вы импортировали fetchBusinesses(), а затем использовали его внутри useEffect, вам не нужно было бы добавлять его в массив зависимостей. Вот как мы на самом деле настроили наши приложения Redux: мы всегда импортируем создателей действий и запускаем их внутри useEffect, не добавляя их в массив зависимостей.

То же верно и для useMemo.

osmancakirio
24 августа 2021 в 07:59
1

вы все равно получите предупреждение, даже если импортируете функцию из своего магазина. Потому что ваши функции будут переданы объекту props через вызов mapDispatchToProps или с использованием второго аргумента тега connect. connect(mapStateToProps, {fetchBusinesses})(Component)

ndtreviv
28 октября 2021 в 14:12
0

@osmancakirio Вы нашли решение предупреждения в этом случае? У меня точно такая же проблема...

osmancakirio
3 ноября 2021 в 16:19
1

@ndtreviv Я провел рефакторинг компонентов, чтобы теперь вместо тега подключения использовались редукционные крючки. затем я передаю функцию отправки массиву зависимостей. Это также рекомендуется разработчиками redux, поскольку, как они говорят, это безопасно, потому что ссылка на функцию отправки почти никогда не меняется.

avatar
syarul
9 декабря 2020 в 06:56
2

Что ж, если вы хотите взглянуть на это по-другому, вам просто нужно знать, какие опции есть у React, кроме exhaustive-deps. Одна из причин, по которой вам не следует использовать функцию замыкания внутри эффекта, заключается в том, что при каждом рендеринге он будет воссоздан/уничтожен снова.

Таким образом, есть несколько методов React в хуках, которые считаются стабильными и неисчерпаемыми, где вам не нужно применять к зависимостям useEffect и, в свою очередь, не нарушать правила взаимодействия react-hooks/exhaustive-deps. Например, вторая возвращаемая переменная useReducer или useState, которая является функцией.

const [,dispatch] = useReducer(reducer, {});

useEffect(() => {
    dispatch(); // Non-exhausted - ESLint won't nag about this
}, []);

Так что, в свою очередь, все ваши внешние зависимости могут сосуществовать с вашими текущими зависимостями в вашей функции-редукторе.

const [,dispatch] = useReducer((current, update) => {
    const { foobar } = update;
    // Logic

    return { ...current, ...update };
}), {});

const [foobar, setFoobar] = useState(false);

useEffect(() => {
    dispatch({ foobar }); // non-exhausted `dispatch` function
}, [foobar]);
avatar
Manish
9 октября 2020 в 22:49
0

Просто передайте функцию в качестве аргумента в массиве useEffect...

useEffect(() => {
   functionName()
}, [functionName])
avatar
Kashif
11 июля 2020 в 10:19
5

Попробуйте так:

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

и

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

Это работает для вас.

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

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();
}, []);

Если вы получаете данные на базе определенного id, то добавьте в callback useEffect [id]. Тогда он не может показать вам предупреждение React Hook useEffect has a missing dependency: 'any thing'. Either include it or remove the dependency array

avatar
Yasin
19 мая 2020 в 13:02
11
const [mount, setMount] = useState(false)
const fetchBusinesses = () => {
   // Function definition
}
useEffect(() => {
   if(!mount) {
      setMount(true);
      fetchBusinesses();
   }
},[fetchBusinesses, mount]);

Это решение довольно простое, и вам не нужно переопределять предупреждения ESLint. Просто сохраните флаг, чтобы проверить, смонтирован ли компонент или нет.

Zhivko Zhelev
14 декабря 2020 в 10:29
1

И вы будете делать это каждый раз, когда вам понадобится componentDidMount?

Preston
15 сентября 2021 в 20:40
1

Затем это пометит вас, что вам нужно добавить mount в качестве зависимости от useEffect.

avatar
Behnam Azimi
13 апреля 2020 в 07:21
5

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

Если вы не хотите помещать fetchBusinesses в зависимости хука, вы можете просто передать его в качестве аргумента функции обратного вызова хука и установить для него основной fetchBusinesses в качестве значения по умолчанию следующим образом:

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

Это не лучшая практика, но в некоторых случаях она может быть полезна.

Кроме того, как Shubham написал, вы можете добавить приведенный ниже код, чтобы указать ESLint игнорировать проверку вашего хука.

// eslint-disable-next-line react-hooks/exhaustive-deps
avatar
Jordan Daniels
30 марта 2020 в 16:24
21

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

Однако, если вы хотите удалить предупреждения во всем проекте, вы можете добавить это в конфигурацию ESLint:

  {
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/exhaustive-deps": 0
    }
  }
avatar
jpenna
20 февраля 2020 в 20:17
315

Есть очень хорошие варианты библиотек управления состоянием, если вы создаете новое приложение или обладаете достаточной гибкостью. Проверьте отдачу.

Для полноты картины:

1. (Перестал работать) Использовать функцию как useEffect обратный вызов

useEffect(fetchBusinesses, [])

2. Объявить функцию внутри useEffect()

useEffect(() => {
  function fetchBusinesses() {
    ...
  }
  fetchBusinesses()
}, [])

3. Запомнить с useCallback()

В этом случае, если у вас есть зависимости в вашей функции, вам придется включить их в массив зависимостей useCallback, и это снова вызовет useEffect, если параметры функции изменятся. Кроме того, это много шаблонного... Так что просто передайте функцию непосредственно useEffect как в 1. useEffect(fetchBusinesses, []).

const fetchBusinesses = useCallback(() => {
  ...
}, [])
useEffect(() => {
  fetchBusinesses()
}, [fetchBusinesses])

4. Аргумент функции по умолчанию

По предложению Бехнама Азими

Это не лучшая практика, но в некоторых случаях она может быть полезна.

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

5. Создайте пользовательский хук

Создайте пользовательский хук и вызывайте его, когда вам нужно запустить функцию только один раз. Может быть чище. Вы также можете вернуть обратный вызов для сброса повторного запуска «инициализации», когда это необходимо.

// customHooks.js
const useInit = (callback, ...args) => {
  const [mounted, setMounted] = useState(false)
  
  const resetInit = () => setMounted(false)

  useEffect(() => {
     if(!mounted) {
        setMounted(true);
        callback(...args);
     }
  },[mounted, callback]);

  return [resetInit]
}

// Component.js
return ({ fetchBusiness, arg1, arg2, requiresRefetch }) => {
  const [resetInit] = useInit(fetchBusiness, arg1, arg2)

  useEffect(() => {
    resetInit()
  }, [requiresRefetch, resetInit]);

6. Отключить предупреждение eslint

Отключение предупреждений должно быть вашим последним средством, но когда вы это сделаете, лучше сделать это встроенным и явным образом, потому что будущие разработчики могут запутаться или создать неожиданные ошибки, не зная, что линтинг отключен

useEffect(() => {
  fetchBusinesses()
}, []) // eslint-disable-line react-hooks/exhaustive-deps
Rohan Shenoy
2 сентября 2020 в 13:48
4

Можно ли отключить предупреждение eslint?

jpenna
2 сентября 2020 в 18:12
29

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

Rohan Shenoy
3 сентября 2020 в 04:32
0

В последней реакции. Если я объявляю состояние, а компонент использует useEffect, отображается предупреждение. Таким образом, в этом случае решения 1, 2 и 3 неприменимы, так как я хочу, чтобы они выполнялись только один раз. Что я должен делать?

jpenna
4 сентября 2020 в 15:36
0

@RohanShenoy Если я правильно понимаю, вы хотите использовать состояние внутри useEffect, это совершенно другая ситуация. В этом случае вы можете только отключить предупреждение, потому что теперь у вас есть вторая внешняя зависимость

Emile Bergeron
16 декабря 2020 в 19:49
3

useEffect(fetchBusinesses, []) выдаст "TypeError: Функция эффекта не должна возвращать ничего, кроме функции, которая используется для очистки." , так как fetchBusinesses возвращает обещание.

jpenna
17 декабря 2020 в 01:44
0

@EmileBergeron Это правда с реализацией OP! Они могли бы просто удалить return из fetchBusinesses, так как это не требуется.

Shani Kehati
11 февраля 2021 в 10:49
0

@EmileBergeron useEffect не следует передавать асинхронной функции, это можно сделать так: useEffect( () => { asyncFunc() } ,[])

Lane
20 февраля 2021 в 09:19
0

// eslint-disable-line react-hooks/exhaustive-deps работает как шарм.

ericjam
31 марта 2021 в 14:42
2

Первое предложение на удивление не устраняет предупреждение

CrazyDev
19 сентября 2021 в 20:35
0

Это БОЛЬШЕ НЕ РАБОТАЕТ!!!!

Daniel Tkach
8 октября 2021 в 17:29
0

Есть ли разница, если функция асинхронная? Это то, что я делаю, это правильно? const loadAgents = useCallback(async ()=> { try { ... const response = await axios.post(...); setAgentsData(response.data); } catch (e) { ... } finally { .. . } }, []); useEffect(() => { if (...) loadAgents(); }, [uiState.selectedSwitch, loadAgents]);

Lewy Blue
25 декабря 2021 в 23:58
0

Обратите внимание, мне нужно было поставить // eslint-disable-next-line react-hooks/exhaustive-deps, а не // eslint-disable-line react-hooks/exhaustive-deps

jpenna
27 декабря 2021 в 12:46
1

@LewyBlue это потому, что вы добавили комментарий над строкой зависимостей

avatar
Stephane L
23 июня 2019 в 10:52
20

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

Функция fetchBusinesses изменяет зависимости хука useEffect (в строке NN) при каждом рендеринге. Чтобы это исправить, оберните определение fetchBusinesses в собственный хук useCallback()

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

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

khan
8 сентября 2021 в 18:36
1

В моем случае этот хук useCallBack решил мою проблему. Подробности см. в документации

avatar
5ervant - techintel.github.io
5 июня 2019 в 18:32
2

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

React.useEffect(() => {
  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]);

  // ...
}
Harvester Haidar
25 июня 2021 в 02:04
0

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

avatar
user3550446
22 мая 2019 в 10:35
9

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

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

Таким образом, вы используете его точно так же, как компонент монтируется (вызывается один раз).

обновлено

или

const fetchBusinesses = useCallback(() => {
 // Your logic in here
 }, [someDeps])

useEffect(() => {
   fetchBusinesses();
// No need to skip the ESLint warning
}, [fetchBusinesses]);

fetchBusinesses будет вызываться каждый раз при изменении someDeps.

rotimi-best
3 июня 2019 в 07:33
0

вместо отключения просто сделайте следующее: [fetchBusinesses] автоматически удалит предупреждение, и это решило проблему для меня.

user210757
18 июня 2019 в 21:43
10

@RotimiBest - это приводит к бесконечному повторному рендерингу, как описано в вопросе.

rotimi-best
19 июня 2019 в 10:35
0

На самом деле я сделал это в одном из своих проектов некоторое время назад, и это не привело к бесконечному циклу. Я проверю еще раз, хотя.

rotimi-best
25 января 2020 в 05:51
2

@ user210757 Подождите, но почему это вызовет бесконечный цикл, ведь вы не устанавливаете состояние после получения данных с сервера. Если вы обновляли состояние, просто напишите условие if перед вызовом функции в useEffect, которая проверяет, пусто ли состояние.

user210757
26 января 2020 в 18:34
0

@rotimi-best прошло некоторое время с тех пор, как я прокомментировал, но я бы сказал, что функция воссоздается каждый раз, поэтому никогда не бывает одинаковой, поэтому всегда будет повторно отображаться, если вы не перейдете в тело useEffect или useCallback.

Joe
29 января 2020 в 12:42
0

см. это полезное обсуждение: github.com/facebook/create-react-app/issues/6880

Peter Mortensen
15 июля 2021 в 09:16
0

Что вы подразумеваете под "точно так же, как смонтировал компонент" (кажется непонятным)? Пожалуйста, ответьте, отредактировав (изменив) свой ответ, а не здесь, в комментариях (без «Редактировать:», «Обновить:» или подобное — ответ должен выглядеть так, как если бы он был написан сегодня).

avatar
r g
25 апреля 2019 в 07:32
152
./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

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

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

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

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

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

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

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

  /*...*/
}

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

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

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

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

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

  /*...*/
}

Или просто определите функцию в useEffect.

Подробнее: [ESLint] Отзыв о правиле lint 'exhaustive-deps' #14920

cesarlarsson
9 января 2020 в 19:12
2

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

avatar
helloitsjoe
25 апреля 2019 в 01:51
5

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

По существу, включите определение функции выборки внутрь useEffect:

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

  fetchBusinesses();
}, []);