Por lo que entiendo, el código asíncrono dentro useEffect se ejecuta sin bloquear el proceso de renderizado. Así que si tengo un componente como este:
const App = () => { useEffect(() => { const log = () => console.log("window loaded"); window.addEventListener("load", log); return () => { window.removeEventListener("load", log); }; }, []); useEffect(() => { const getData = async () => { console.log("begin"); const response = await fetch( "https://jsonplaceholder.typicode.com/todos/1" ); const data = await response.json(); console.log("end"); }; getData(); }, []); return null; };La salida de la consola es (en orden):
begin window loaded end
Sin embargo, si uso la importación dinámica ES2020 dentro de useEffect:
const App = () => { useEffect(() => { const log = () => console.log("window loaded"); window.addEventListener("load", log); return () => { window.removeEventListener("load", log); }; }, []); useEffect(() => { const getData = async () => { console.log("begin"); const data = await import("./data.json"); console.log("end"); }; getData(); }, []); return null; };La salida es (en orden):
begin end window loaded
Esto es un problema porque cuando data.json es muy grande, el navegador se bloquea al importar el archivo grande antes de que React procese algo.
Toda la información necesaria y útil está en los comentarios de Terry. aquí está la implementación de lo que quieres según los comentarios:
Primer objetivo:
Me gustaría importar los datos después de que se haya cargado la ventana por razones de SEO.
Segundo gol:
En mi caso, el archivo que intento importar dinámicamente es en realidad una función que requiere un gran conjunto de datos. Y quiero ejecutar esta función cada vez que algún estado haya cambiado, por eso lo puse en un enlace useEffect.
Puede crear una función para obtener los datos tal como los creó como getData con useCallback hook para usarlos en cualquier lugar sin problemas.
import React, {useEffect, useState, useCallback} from 'react'; function App() { const [data, setData] = useState({}); const [counter, setCounter] = useState(0); const getData = useCallback(async () => { try { const result = await import('./data.json'); setData(result); } catch (error) { // do a proper action for failure case console.log(error); } }, []); useEffect(() => { window.addEventListener('load', () => { getData().then(() => console.log('data loaded successfully')); }); return () => { window.removeEventListener('load', () => { console.log('page unmounted'); }); }; }, [getData]); useEffect(() => { if (counter) { getData().then(() => console.log('re load data after the counter state get change')); } }, [getData, counter]); return ( <div> <button onClick={() => setCounter((prevState) => prevState + 1)}>Increase Counter</button> </div> ); } export default App; Con el componente montado, el detector de eventos cargará data.json en el evento 'cargar'. Hasta ahora, el primer objetivo se ha cumplido.
Utilizo un contador simple y de muestra para demostrar el cambio en el estado y volver a cargar el escenario data.json . Ahora, con cada cambio en el valor del counter , la función getData llamará porque el segundo useEffect tiene el contador en su conjunto de dependencias. Ahora el segundo objetivo se ha cumplido.
Nota: El bloque if en el segundo useEffect evita que getData llame después de que el componente se montó y la primera invocación de useEffect
Nota: No olvide usar el bloque catch para casos de falla.
Nota: Configuré el resultado de getData en el estado de los data , puede hacer un enfoque diferente para este resultado, pero las otras lógicas son las mismas.