Cuando ejecuto el código a continuación, aparece el error "No se pueden leer las propiedades de nulo (leyendo 'iniciar sesión')", porque llega a la declaración de devolución al final, lo que no debería hacer, ya que ya he verificado el valor booleano antes de la devolución.
import React, { useState, useEffect } from 'react'; const url = 'https://api.github.com/users/QuincyLarsn'; const MultipleReturns = () => { const [isLoading, setIsLoading] = useState(true); const [isError, setIsError] = useState(false); const [user, setUser] = useState(null); useEffect(() => { fetch(url) .then(data => { if (data.status >= 200 && data.status <= 299) return data.json(); else { console.log("here"); setIsLoading(false); setIsError(true); console.log("here 2"); } }) .then(result => { setIsLoading(false); setUser(result); }) .catch(error => console.log(error)) }, []); console.log(isError); if (isLoading) return <h2>Loading...</h2> if (isError) { return <h2>Error...</h2> } return <h2>{user.login}</h2> }; export default MultipleReturns;En el código anterior, si setIsError(true) se coloca antes de setIsLoading(false) en useEffect, entonces todo funciona bien, pero no al revés, de manera similar, si la URL es correcta, las cosas también funcionan bien si setUser(result) se coloca antes de setIsLoading(false ) y no al revés. No soy capaz de averiguar por qué ese es el caso.
React no procesa actualizaciones de estado por lotes desde fetch() . Se procesa por lotes en caso de detectores de eventos. Esta es una llamada de recuperación asíncrona.
En esta consola de espacio aislado, puede ver que hay una representación entre sus actualizaciones de estado: setIsLoading setIsLoading(false) y setIsError(true) .
Entonces, para un ciclo de procesamiento: isLoading es falso e isError también es falso. Eso conducirá a la condición de error.
Puede usar unstable_batchedUpdates para aplicar el procesamiento por lotes.
import { useEffect, useState } from "react"; import { unstable_batchedUpdates } from "react-dom"; import "./styles.css"; const url = "https://api.github.com/users/QuincyLarsn"; const App = () => { const [isLoading, setIsLoading] = useState(true); const [isError, setIsError] = useState(false); const [user, setUser] = useState(null); useEffect(() => { fetch(url) .then((data) => { if (data.status >= 200 && data.status <= 299) return data.json(); else { console.log("here"); unstable_batchedUpdates(() => { setIsLoading(false); setIsError(true); }); console.log("here 2"); } }) .then((result) => { setIsLoading(false); setUser(result); }) .catch((error) => { console.log(error); }); }, []); console.log("isError", isError); if (isLoading) return <h2>Loading...</h2>; if (isError) return <h2>Error...</h2>; return <h2>{user.login}</h2>; }; export default App;En tal caso, el orden sí importa.
Si bien React puede realizar actualizaciones por lotes en este caso, no está garantizado e incluso si lo hace, puede llamar a la función de procesamiento con el estado intermedio.
Entonces, cuando isLoading se establece en false , pero user aún no está configurado, obtiene un error.
Puede solucionar esto configurando el user primero y luego haciendo que isLoading false .
Pero la solución real sería eliminar las variables de estado innecesarias: isLoading es true , mientras que isError es false y user es null , y false en caso contrario.
Entonces, puedes hacerlo así:
no debería, ya que ya tengo controles para el valor booleano antes de regresar.
import React, { useState, useEffect } from 'react'; const url = 'https://api.github.com/users/QuincyLarsn'; const MultipleReturns = () => { const [isError, setIsError] = useState(false); const [user, setUser] = useState(null); useEffect(() => { fetch(url) .then(data => { if (data.status >= 200 && data.status <= 299) return data.json(); else { console.log("here"); setIsError(true); console.log("here 2"); } }) .then(result => { setUser(result); }) .catch(error => console.log(error)) }, []); console.log(isError); if (isError) { return <h2>Error...</h2> } if (user !== null) { return <h2>{user.login}</h2> } return <h2>Loading...</h2> }; export default MultipleReturns;Después de configurar isLoading como falso, el código se mueve a la última declaración de retorno ya que el error sigue siendo falso en este momento. Entonces, primero establecer el error bloquea el código en la segunda declaración de devolución.
De manera similar, si configura isLoading como falso y luego configura el usuario, el código se moverá a la última declaración de devolución antes de que se configure el usuario y mostrará un error. Establecer al usuario y luego hacer que isLoading sea falso muestra al usuario perfectamente.