Así que he estado reiterando mi código y trabajando con él durante algunas horas y necesito ayuda. Mi objetivo era usar useEffect para cargar una llamada API desde una API de horóscopo. Me encontré con este error en el que solo podía ver los datos DESPUÉS de cargar otra página del sitio web y volver a mostrar la página de inicio. Mi objetivo era ver los datos mostrados inicialmente en useEffect() desde que lo llamé. Sin embargo, parece que no funciona. No estoy seguro si necesito usar setInitialState o manipular la forma en que estoy exportando los valores a través del contexto.
En más especulaciones, de alguna manera veo cuál es el problema en mi código, pero no tengo idea de CÓMO usar setInitialState para cargar valores desde la API.
initialState.data.yesterday = data;¿Guardo esto en una variable y luego llamo a establecer datos en esa variable?
1.) Intenté manipular el estado lo mejor que pude.
2.) La página nunca carga datos de API en la primera ejecución, solo muestra datos después de hacer clic en un botón
3.) El código parece necesitar setInitialDate pero no puede encontrar una solución razonable combinada con useEffect para obtener los datos correctos.
¡¡Gracias!!
Estoy dispuesto a escuchar todas las soluciones óptimas para mi problema. Ni siquiera estoy seguro de si voy en la dirección correcta. Gracias.
const [initialState, setInitialState] = useState({ data: { yesterday: {}, today: {}, tomorrow: {}, } }); useEffect(() => { console.log("useEffect called"); // eslint-disable-next-line react-hooks/exhaustive-deps async function getDayInfos() { try { const response = await axios.post('https://aztro.sameerkumar.website/?sign=aries&day=yesterday'); const data = response.data initialState.data.yesterday = data; } catch (error) { console.error(error); } try { const response = await axios.post('https://aztro.sameerkumar.website/?sign=aries&day=today'); initialState.data.today = response.data } catch (error) { console.error(error); } try { const response = await axios.post('https://aztro.sameerkumar.website/?sign=aries&day=tomorrow'); initialState.data.tomorrow = response.data } catch (error) { console.error(error); } } getDayInfos() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) return <AstroContext.Provider value={{initialState}}> {children} </AstroContext.Provider>}
React necesita que llames al setter (por ejemplo setInitialState ) para saber que has cambiado algo que podría requerir una nueva representación.
Entiendo que es tentador tratar de hacer manipulaciones de objetos cuando tiene campos anidados en su estado, pero dado que sus campos están cambiando básicamente todos a la vez, podemos hacerlo atómicamente y mejorar su tiempo para obtener los primeros datos significativos. .
Aparte, creo que initialState podría no ser una buena idea para el nombre de su variable. Llamémoslo dayInfo porque eso es lo que es. También necesitamos representar el estado de la aplicación mientras se cargan los datos: podrá mostrar una interfaz de usuario de carga, puede deshacerse de esa matriz de dependencia useEffect() vacía (y el comentario de desactivación de ESLint) y también ayuda mucho a la depuración.
Sin más preámbulos, aquí hay una versión funcional:
// Document the shape of our state: const initialState = { yesterday: {}, today: {}, tomorrow: {} }; // Helper function that just gets a single day (to avoid repetition) const fetchDay = async (day) => { try { const response = await axios.post( `https://aztro.sameerkumar.website/?sign=aries&day=${day}` ); return response.data; } catch (error) { console.error(error); } }; export default function App() { const [loadingState, setLoadingState] = useState("NOT_LOADED"); const [dayInfo, setDayInfo] = useState(initialState); useEffect(() => { // Only go fetch the data if we haven't tried to yet if (loadingState === "NOT_LOADED") { setLoadingState("IN_PROGRESS"); getDayInfos(); } }, [loadingState]); async function getDayInfos() { // Fire off the three requests concurrently ... const yesterdayPromise = fetchDay("yesterday"); const todayPromise = fetchDay("today"); const tomorrowPromise = fetchDay("tomorrow"); // ... but wait for them all to resolve here const [yesterday, today, tomorrow] = await Promise.all([ yesterdayPromise, todayPromise, tomorrowPromise ]); setDayInfo({ yesterday, today, tomorrow }); setLoadingState("LOADED"); } ... }Ahora hemos aclarado exactamente cuándo vamos a ir a buscar los datos.
También estamos usando Promises de manera más efectiva, disparando las tres recuperaciones de Axios al mismo tiempo, en lugar de una por una. Finalmente, establecemos atómicamente el estado de dayInfo y también indicamos que tenemos los datos, para evitar recuperarlos nunca más, mucho más seguro que una matriz de dependencias vacía.
A la respuesta de @millhouse, solo agrego que siempre es una buena idea en React, o Redux, mantener sus datos lo más planos posible, ya que necesita realizar todas las operaciones inmutables en sus datos para activar las re-renderizaciones, y si no son lo suficientemente cuidadosos y tienen objetos anidados profundos, es posible que tenga objetos nuevos con objetos anidados referenciados antiguos que causen todo tipo de comportamientos sutiles. Si se ve obligado a utilizar estructuras de datos anidadas profundas, pruebe Immer, que es una gran biblioteca que le permite mutar una propiedad anidada profunda de un objeto directamente con el mismo resultado de una operación totalmente inmutable.