Jak naprawić brakujące ostrzeżenie o zależnościach podczas używania Hooka Reacta useEffect?

W Reaccie 16.8.6 (było dobrze w poprzedniej wersji 16.8.3), pojawia się ten błąd, gdy próbuję zapobiec nieskończonej pętli w żądaniu pobierania

./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
Nie udało mi się znaleźć rozwiązania, które zatrzyma nieskończoną pętlę. Chcę trzymać się z dala od używania useReducer(). Znalazłem tę dyskusję https://github.com/facebook/react/issues/14920 gdzie możliwe rozwiązanie jest You can always // eslint-disable-next-line react-hooks/exhaustive-deps if you think you know what you're doing. nie jestem pewien tego, co robię, więc jeszcze nie próbowałem go wdrożyć.

I czy ta bieżąca konfiguracja react hook useEffect działa bez przerwy / nieskończona pętla i jedyny komentarz dotyczy useCallback(), z którym nie jestem zaznajomiony.

Jak obecnie używam useEffect() (które chcę uruchomić tylko raz na początku podobne do 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
      });
  };
Author: HoldOffHunger, 2019-04-25

14 answers

Jeśli nie używasz metody fetchBusinesses gdziekolwiek poza efektem, możesz po prostu przenieść ją do efektu i uniknąć ostrzeżenia

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

Jeśli jednak używasz fetchBusinesses poza renderowaniem, musisz zwrócić uwagę na dwie rzeczy

  1. Czy Jest jakiś problem z Tobą Nie przekazywaniem fetchBusinesses jako metody, gdy jest używana podczas montowania z zamknięciem zamykającym?
  2. Czy twoja metoda zależy od pewnych zmiennych, które otrzymuje z jej zamknięcia? To nie dla Ciebie.
  3. przy każdym renderowaniu, fetchBusinesses zostanie ponownie utworzony i dlatego przekazanie go do useEffect spowoduje problemy. Więc najpierw musisz zapamiętać fetchBusinesses, jeśli chcesz przekazać je do tablicy zależności.

Podsumowując powiedziałbym, że jeśli używasz fetchBusinesses poza useEffect możesz wyłączyć regułę używając // eslint-disable-next-line react-hooks/exhaustive-deps w przeciwnym razie możesz przenieść metodę wewnątrz useEffect

Aby wyłączyć regułę napiszesz ją jak

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

   // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) 
 332
Author: Shubham Khatri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-31 19:42:44

Możesz ustawić go bezpośrednio jako useEffect callback:

useEffect(fetchBusinesses, [])

Uruchomi się tylko raz, więc upewnij się, że wszystkie zależności funkcji są prawidłowo ustawione (tak samo jak przy użyciu componentDidMount/componentWillMount...)


Edit 02/21/2020

Tylko dla kompletności:

1. Użyj funkcji jako wywołania zwrotnego useEffect (Jak wyżej)

useEffect(fetchBusinesses, [])

2. Declare function inside useEffect()

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

3. Memoize with useCallback()

W tym przypadku, jeśli masz zależności w twoja funkcja, będziesz musiał uwzględnić je w tablicy useCallback dependencies i to uruchomi useEffect ponownie, jeśli paramy funkcji ulegną zmianie. Poza tym jest to dużo kotła... Więc po prostu przekaż funkcję bezpośrednio do {[5] } jak w 1. useEffect(fetchBusinesses, []).

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

4. Wyłącz Ostrzeżenie eslinta

useEffect(() => {
  fetchBusinesses()
}, []) // eslint-disable-line react-hooks/exhaustive-deps
 168
Author: jpenna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-30 12:51:09
./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

To nie jest błąd JS/React, ale Ostrzeżenie eslint (eslint-plugin-react-hooks).

Mówi ci, że hook zależy od funkcji fetchBusinesses, więc powinieneś przekazać go jako zależność.

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

Może spowodować wywołanie funkcji przy każdym renderowaniu, jeśli funkcja jest zadeklarowana w komponencie takim jak:

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

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

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

  /*...*/
}

Ponieważ każda funkcja czasowa jest redeclared z nowym odniesieniem

Prawidłowy sposób robienia tego to:

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

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

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

  /*...*/
}

Lub po prostu definiowanie funkcji w useEffect

Więcej: https://github.com/facebook/react/issues/14920

 113
Author: r g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-11 12:25:30

Rozwiązanie jest również podane przez Reacta, który radzi ci użyć useCallback, który zwróci wersję memoize twojej funkcji:

Funkcja 'fetchBusinesses' powoduje, że zależności Hooka useEffect (w linii NN) zmieniają się przy każdym renderowaniu. Aby to naprawić, zawiń definicję 'fetchBusinesses' w własną metodę Usecallback () Hook react-hooks/exhaustive-deps

useCallback jest prosty w użyciu, ponieważ ma ten sam podpis co useEffect różnica polega na tym, że useCallback zwraca funkcja. Wyglądałoby to tak:

 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]);
 12
Author: Stephane L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-18 03:34:39

Te ostrzeżenia są bardzo pomocne w znajdowaniu komponentów, które nie aktualizują się konsekwentnie: https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies.

Jeśli jednak chcesz usunąć ostrzeżenia w całym projekcie, możesz dodać je do konfiguracji eslint:

  {
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/exhaustive-deps": 0
    }
  }
 4
Author: Jordan Daniels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-30 16:24:38
const [mount, setMount] = useState(false)
const fetchBusinesses = () => { 
   //function defination
}
useEffect(() => {
   if(!mount) {
      setMount(true);
      fetchBusinesses();
   }
},[fetchBusinesses]);

To rozwiązanie jest dość proste i nie trzeba nadpisywać ostrzeżeń es-lint. Wystarczy utrzymać flagę, aby sprawdzić, czy komponent jest zamontowany, czy nie.

 3
Author: Yasin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-19 13:02:40

Ten artykuł jest dobrym wstępem do pobierania danych za pomocą hooków: https://www.robinwieruch.de/react-hooks-fetch-data/

Zasadniczo, Dołącz definicję funkcji fetch wewnątrz useEffect:

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

  fetchBusinesses();
}, []);
 2
Author: helloitsjoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-25 01:51:31

Możesz usunąć tablicę typu drugiego argumentu [], ale fetchBusinesses() będzie również wywoływana przy każdej aktualizacji. Możesz dodać IF do implementacji fetchBusinesses(), Jeśli chcesz.

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

Drugim jest zaimplementowanie funkcji fetchBusinesses() Poza komponentem. Tylko nie zapomnij przekazać argumentów zależności do wywołania fetchBusinesses(dependency), jeśli takie istnieją.

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

  // ...
}
 2
Author: 5ervant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-05 18:32:01

You try this way

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

I

useEffect(() => {
    fetchBusinesses();
  });
To praca dla Ciebie. Ale moja sugestia to spróbować w ten sposób również pracować dla Ciebie. Jest lepiej niż wcześniej. Używam w ten sposób:
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();
      }, []);

Jeśli otrzymasz dane na podstawie określonego identyfikatora, Dodaj w callback useEffect [id] to nie możesz wyświetlić Ostrzeżenia React Hook useEffect has a missing dependency: 'any thing'. Either include it or remove the dependency array

 2
Author: Kashif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 10:25:56

Wystarczy przekazać funkcję jako argument w tablicy useEffect...

useEffect(() => {
   functionName()
}, [functionName])
 2
Author: Manish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-09 22:49:57

Właściwie ostrzeżenia są bardzo przydatne podczas tworzenia hooków. ale w niektórych przypadkach może cię igiełkować. zwłaszcza, gdy nie trzeba słuchać zmian zależności.

Jeśli nie chcesz umieszczać fetchBusinesses wewnątrz zależności Hooka, możesz po prostu przekazać go jako argument do wywołania zwrotnego Hooka i ustawić główną fetchBusinesses jako domyślną wartość w ten sposób

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

Nie jest to najlepsza praktyka , ale może być przydatna w niektórych przypadkach.

Również jako Shubnam napisał, możesz dodać poniższy kod, aby powiedzieć ESLint, aby zignorował sprawdzanie twojego Hooka.
// eslint-disable-next-line react-hooks/exhaustive-deps
 1
Author: Behnam Azimi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-13 07:21:43

Cóż, jeśli chcesz spojrzeć na to inaczej, musisz tylko wiedzieć, jakie są opcje, czy React ma to nie exhaustive-deps? Jednym z powodów, dla których nie powinieneś używać funkcji zamknięcia wewnątrz efektu jest to, że przy każdym renderowaniu zostanie ona ponownie utworzona/zniszczona.

Istnieje więc wiele metod Reactowych w hookach, które są uważane za stabilne i nie wyczerpujące, gdzie nie trzeba stosować zależności useEffect, a z kolei nie będą łamać reguł react-hooks/exhaustive-deps. Na przykład drugi zwraca zmienną useReducer lub useState, która jest funkcją.

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

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

Więc z kolei możesz mieć wszystkie zewnętrzne zależności razem z bieżącymi zależnościami współistnieć razem w swojej funkcji reduktora.

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]);
 1
Author: syarul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-09 06:56:01

Dodaj ten komentarz na górze pliku, aby wyłączyć ostrzeżenie.

/* eslint-disable react-hooks/exhaustive-deps */
 0
Author: Sandeep Dhungana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-10 04:10:33

Po prostu wyłącz eslint dla następnej linii;

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

W ten sposób używasz go tak, jak komponent montował (nazywany kiedyś)

Zaktualizowano

Lub

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

useEffect(() => {
   fetchBusinesses();
// no need to skip eslint warning
}, [fetchBusinesses]); 

FetchBusinesses będą wywoływane za każdym razem, gdy coś się zmieni

 -1
Author: user3550446,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-27 23:19:52