Con React 16.8.6 (era bueno en la versión anterior 16.8.3), aparece este error cuando intento evitar un bucle infinito en una solicitud de búsqueda:
./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
No he podido encontrar una solución que detenga el bucle infinito. Quiero evitar usar useReducer()
. Encontré esta discusión [ESLint] Comentarios para la regla de pelusa 'exhaustive-deps' # 14920 donde una posible solución es You can always // eslint-disable-next-line react-hooks/exhaustive-deps if you think you know what you're doing.
No estoy seguro de lo que estoy haciendo, así que no he intentado implementarlo todavía.
Tengo esta configuración actual, React hook useEffect se ejecuta continuamente para siempre/bucle infinito y el único comentario es sobre useCallback()
con el que no estoy familiarizado.
Cómo estoy usando actualmente useEffect()
(que solo quiero ejecutar una vez al principio, similar a 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 }); };
Si no está utilizando el método fetchBusinesses en ningún lugar aparte del efecto, simplemente puede moverlo al efecto y evitar la advertencia.
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(); }, []);
Sin embargo, si está utilizando fetchBusinesses fuera del renderizado, debe tener en cuenta dos cosas
fetchBusinesses
como método cuando se usa durante el montaje con su cierre adjunto? Para resumir, diría que si está utilizando fetchBusinesses
fuera de useEffect
, puede deshabilitar la regla usando // eslint-disable-next-line react-hooks/exhaustive-deps
lo contrario, puede mover el método dentro de useEffect
Para deshabilitar la regla, la escribirías así
useEffect(() => { // other code ... // eslint-disable-next-line react-hooks/exhaustive-deps }, [])
Hay muy buenas opciones para la gestión de bibliotecas estatales si está creando una nueva aplicación o tiene suficiente flexibilidad. Echa un vistazo a Retroceso.
Solo para completar:
useEffect
useEffect(fetchBusinesses, [])
useEffect()
useEffect(() => { function fetchBusinesses() { ... } fetchBusinesses() }, [])
useCallback()
En este caso, si tiene dependencias en su función, tendrá que incluirlas en la matriz de dependencias useCallback
y esto activará useEffect
nuevamente si los parámetros de la función cambian. Además, es un montón de repeticiones... Así que simplemente pase la función directamente a useEffect
como en 1. useEffect(fetchBusinesses, [])
.
const fetchBusinesses = useCallback(() => { ... }, []) useEffect(() => { fetchBusinesses() }, [fetchBusinesses])
Según lo sugerido por Behnam Azimi
No es la mejor práctica, pero podría ser útil en algunos casos.
useEffect((fetchBusinesses = fetchBusinesses) => { fetchBusinesses(); }, []);
Cree un enlace personalizado y llámelo cuando necesite ejecutar la función solo una vez. Puede ser más limpio. También puede devolver una devolución de llamada para restablecer y volver a ejecutar la "inicialización" cuando sea necesario.
// 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]);
La desactivación de las advertencias debe ser su último recurso, pero cuando lo haga, es mejor que lo haga en línea y de forma explícita , ya que los futuros desarrolladores pueden confundirse o crear errores inesperados sin saber que el linting está desactivado.
useEffect(() => { fetchBusinesses() }, []) // eslint-disable-line react-hooks/exhaustive-deps
./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
No es un error de JavaScript/React, sino una advertencia de ESLint (eslint-plugin-react-hooks).
Te dice que el enlace depende de la función fetchBusinesses
, por lo que debes pasarlo como una dependencia.
useEffect(() => { fetchBusinesses(); }, [fetchBusinesses]);
Podría resultar en invocar la función en cada renderizado si la función se declara en un componente como:
const Component = () => { /*...*/ // New function declaration every render const fetchBusinesses = () => { fetch('/api/businesses/') .then(...) } useEffect(() => { fetchBusinesses(); }, [fetchBusinesses]); /*...*/ }
porque cada vez que la función se redeclara con una nueva referencia.
La forma correcta de hacer esto es:
const Component = () => { /*...*/ // Keep the function reference const fetchBusinesses = useCallback(() => { fetch('/api/businesses/') .then(...) }, [/* Additional dependencies */]) useEffect(() => { fetchBusinesses(); }, [fetchBusinesses]); /*...*/ }
O simplemente defina la función en useEffect
.
Más: [ESLint] Comentarios sobre la regla de pelusa 'exhaustive-deps' #14920