// ACTUALIZAR: El problema era usar el estado inmediatamente después de configurarlo dentro useEffect() . Vea mi respuesta AQUÍ para más detalles.
Estoy tratando de actualizar una de mis páginas de la aplicación React de componente de clase a componente funcional con Hooks. Sin embargo, tengo algunos problemas debido a algunas funciones asíncronas.
La forma en que se comporta la página anterior es que en componentDidMount() algunos datos se obtienen de forma asíncrona de la base de datos y se muestran. Funciona correctamente, myName y myValue se muestran correctamente.
// OLD APPROACH - CLASS COMPONENT class MyPage extends Component { constructor(props) { super(props); this.state = { myName: null, myValue: undefined, } } componentDidMount = async () => { try { const myName = await getNameFromDatabase(); const myValue = await getValueFromDatabase(); this.setState({ myName, myValue }); } catch (error) { alert( "Some errors occured when fetching from DB" ); console.error(error); } } render() { return ( <div> <h1>{this.state.myName}</h1> <h1>{this.state.myValue}</h1> </div> ) } export default MyPageTraté de actualizar la página siguiendo cuidadosamente esta respuesta .
// NEW APPROACH - FUNCTIONAL COMPONENT WITH HOOKS function MyPage() { const [myName, setMyName] = useState(null); const [myValue, setMyValue] = useState(undefined); useEffect(() => { async function fetchFromDatabase() { const myName = await getNameFromDatabase(); const myValue = await getValueFromDatabase(); setMyName(myName); setMyValue(myValue); } fetchFromDatabase(); }, []) return ( <div> <h1>{myName}</h1> <h1>{myValue}</h1> </div> ) } Sin embargo, cuando hago esto, ya no se muestran. Supuse que permanecen "nulos" e "indefinidos". Aparentemente, si hago un console.log() , eventualmente se recuperan, pero solo después de que la página se procesa sin ellos, que no es lo que sucedió en el primer caso.
¿Por qué exactamente sucede esto? ¿Por qué se muestra correctamente en el primer caso pero no en el segundo? Por lo que sé, useEffect() hace lo mismo que componentDidMount() . ¿Debo proceder de otra manera si deseo llamar a funciones asíncronas dentro useEffect() ?
Las actualizaciones de gancho y estado de useEffect están bien. Sin embargo, los componentes de función no tienen instancias, por lo que this simplemente no está definido. Corrija el renderizado para hacer referencia directamente a los valores de estado.
También es una buena práctica controlar los errores cuando se trabaja con código asíncrono.
function MyPage() { const [myName, setMyName] = useState(null); const [myValue, setMyValue] = useState(undefined); useEffect(() => { async function fetchFromDatabase() { try { const myName = await getNameFromDatabase(); const myValue = await getValueFromDatabase(); setMyName(myName); setMyValue(myValue); } catch(error) { // handle any rejected Promises and thrown errors } } fetchFromDatabase(); }, []); return ( <div> <h1>{myName}</h1> <h1>{myValue}</h1> </div> ); }En primer lugar, le está dando el mismo nombre a su respuesta que a su useState(). Intente usar diferentes nombres. Luego, coloque una cadena vacía en su valor predeterminado de useState() en lugar de nulo o indefinido. Finalmente, ya no necesita usar esto , sino acceder directamente al valor. Debería ser algo como esto:
function MyPage() { const [myName, setMyName] = useState(''); const [myValue, setMyValue] = useState(''); useEffect(() => { async function fetchFromDatabase() { const name = await getNameFromDatabase(); const value = await getValueFromDatabase(); setMyName(name); setMyValue(value); } fetchFromDatabase(); }, []) return ( <div> <h1>{myName}</h1> <h1>{myValue}</h1> </div> ) }function MyPage() { const [myName, setMyName] = useState(null); const [myValue, setMyValue] = useState(undefined); useEffect(() => { (async () => { const myName = await getNameFromDatabase(); const myValue = await getValueFromDatabase(); setMyName(myName); setMyValue(myValue); })(); }, []); return ( <div> <h1>{myName}</h1> <h1>{myValue}</h1> </div> ); }