Cómo solucionar la advertencia de dependencia faltante al usar useEffect React Hook
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 recuperación:
./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 alejarme del consumo useReducer()
. Encontré esta discusión [ESLint] Comentarios sobre la regla de pelusa #14920 de 'deps exhaustivos' 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.
que no estoy seguro de lo que estoy haciendo, por lo que no he intentado implementarla todavía.
Tengo esta configuración actual, React hook useEffect se ejecuta continuamente en bucle infinito/indefinido y el único comentario es sobre useCallback()
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 utiliza fetchBusinesses fuera del efecto, debe tener en cuenta dos cosas
- ¿Hay algún problema con que no lo pase
fetchBusinesses
como método cuando se usa durante el montaje con su cierre envolvente? - ¿Su método depende de algunas variables que recibe de su cierre adjunto? Este no es tu caso.
- En cada renderizado, se volverá a crear fetchBusinesses y, por lo tanto, pasarlo a useEffect causará problemas. Entonces, primero debes memorizar fetchBusinesses si fueras a pasarlo a la matriz de dependencia.
Para resumir, diría que si está usando fetchBusinesses
fuera de useEffect
, puede deshabilitar la regla; // eslint-disable-next-line react-hooks/exhaustive-deps
de 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 estatal de bibliotecas si estás creando una nueva aplicación o tienes suficiente flexibilidad. Mira Retroceso.
Sólo para completar:
1. (Dejó de funcionar) Usar la función como useEffect
devolución de llamada
useEffect
devolución de llamadauseEffect(fetchBusinesses, [])
2. Declarar función dentrouseEffect()
useEffect(() => {
function fetchBusinesses() {
...
}
fetchBusinesses()
}, [])
3. Memoriza conuseCallback()
En este caso, si tiene dependencias en su función, tendrá que incluirlas en la useCallback
matriz de dependencias y esto activará useEffect
nuevamente si los parámetros de la función cambian. Además, es un montón de texto repetitivo... Así que simplemente pase la función directamente a useEffect
como en 1. useEffect(fetchBusinesses, [])
.
const fetchBusinesses = useCallback(() => {
...
}, [])
useEffect(() => {
fetchBusinesses()
}, [fetchBusinesses])
4. Argumento predeterminado de la función
Según lo sugerido por Behnam Azimi
No es una buena práctica, pero podría resultar útil en algunos casos.
useEffect((fetchBusinesses = fetchBusinesses) => {
fetchBusinesses();
}, []);
5. Crea un gancho personalizado
Cree un enlace personalizado y llámelo cuando necesite ejecutar la función solo una vez. Puede que esté 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]);
6. Desactive la advertencia de eslint
Deshabilitar las advertencias debería ser su último recurso, pero cuando lo haga, es mejor hacerlo en línea y explícitamente , porque los futuros desarrolladores pueden confundirse o crear errores inesperados sin saber que 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 está diciendo que el gancho 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 la función se vuelve a declarar 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 n.º 14920 de 'deps exhaustivos'
Estas advertencias son muy útiles para encontrar componentes que no se actualizan constantemente: ¿ Es seguro omitir funciones de la lista de dependencias? .
Sin embargo, si desea eliminar las advertencias en todo su proyecto, puede agregar esto a su configuración de ESLint:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/exhaustive-deps": 0
}
}