Una nota sobre el estado de las actualizaciones de React





¡Buen dia amigos!



El gancho useState () administra el estado en los componentes funcionales de React. En los beans de clase, el estado se almacena en this.state y se llama al método this.setState () para actualizar.



Por lo general, no hay nada difícil en trabajar con el estado. Sin embargo, hay un matiz importante asociado con la actualización.



¿Cómo se actualiza el estado: inmediatamente (sincrónicamente) o diferido (asincrónicamente)? Continue leyendo para encontrar la respuesta.



1. Actualización del estado con useState ()



Digamos que tenemos un componente tan funcional:



import { useState } from 'react'

function DoubleIncreaser() {
  const [count, setCount] = useState(0)

  const doubleIncreaseHandler = () => {
    setCount(count + 1)
    setCount(count + 1)
  }

  return (
    <>
      <button onClick={doubleIncreaseHandler}>
        Double Increase
      </button>
      <div>Count: {count}</div>
    </>
  )
}

      
      





const [count, setCount] = useState (0) define el estado inicial del componente. count es una variable que contiene el estado actual y setCount es una función para actualizar este estado.



El componente contiene un botón de doble aumento. Cuando se hace clic en este botón, se llama al controlador doubleIncreaseHandler, que realiza dos actualizaciones sucesivas para contar: setCount (count + 1) y luego setCount (count + 1) nuevamente.



¿Cuál será el estado del componente después de hacer clic en el botón 1 o 2?



Abra esta demostración y haga clic en el botón. El valor del recuento aumentará en 1 después de cada clic.



Cuando setCount (cuenta + 1) actualiza el estado, el valor de la cuenta no cambia inmediatamente. En su lugar, React programa el estado para que se actualice y la próxima vez que se renderice, en const [count, setCount] = useState (0), el gancho asigna un nuevo valor para contar.



Por ejemplo: si el valor de la variable count es 0, entonces llame a setCount (count + 1); setCount (cuenta + 1) se evalúa como setCount (0 + 1); setCount (0 + 1) - que da como resultado 1 como valor de estado en el siguiente render.



Por lo tanto, la actualización del estado usando setValue (newValue) en [value, setValue] = useState () se realiza de forma asincrónica.



Sin embargo, la función de actualización de estado puede tomar una devolución de llamada como argumento para calcular un nuevo estado basado en el actual. En nuestro caso, podemos usar setCount (actualCount => actualCount + 1):



import { useState } from 'react'

function DoubleIncreaser() {
  const [count, setCount] = useState(0)

  const doubleIncreaseHandler = () => {
    setCount(actualCount => actualCount + 1)
    setCount(actualCount => actualCount + 1)
  }

  return (
    <>
      <button onClick={doubleIncreaseHandler}>
        Double Increase
      </button>
      <div>Count: {count}</div>
    </>
  )
}

      
      





Cuando se actualiza el estado mediante dicha función, el argumento actualCount contendrá el valor del estado real.



Abra esta demostración y haga clic en el botón. El recuento aumentará a 2 como se esperaba.



Por supuesto, siempre podemos crear una variable intermedia:



import { useState } from 'react'

function DoubleIncreaser() {
  const [count, setCount] = useState(0)

  const doubleIncrease = () => {
    let actualCount = count
    actualCount = actualCount + 1
    actualCount = actualCount + 1
    setCount(actualCount)
  }

  return (
    <>
      <button onClick={this.doubleIncrease}>
        Double Increase
      </button>
      <div>Count: {count}</div>
    </>
  )
}

      
      





let actualCount = count es una variable intermedia que se puede actualizar a su gusto. Esta variable se usa para actualizar el estado usando setCount (actualCount).



2. El estado es inmutable (inmutable) y de solo lectura



Si olvida que el estado se actualiza en el siguiente renderizado, puede intentar leer el valor inmediatamente después de cambiarlo. Desafortunadamente, no obtendrá nada:



function FetchUsers() {
  const [users, setUsers] = useState([])

  useEffect(() => {
    const startFetching = async () => {
      const response = await fetch('/users')
      const fetchedUsers = await response.json()

      setUsers(fetchedUsers)
      console.log(users)        // => []
      console.log(fetchedUsers) // => ['John', 'Jane', 'Alice', 'Bob']
    }
    startFetching()
  }, [])

  return (
    <ul>
      {users.map(user => <li>{user}</li>)}
    </ul>
  )
}

      
      





El componente FetchUsers envía una solicitud de montaje: startFetching ().



Cuando se reciben datos, setUsers (fetchedUsers) actualiza el estado. Sin embargo, los cambios no ocurren de la noche a la mañana.



La variable de usuarios es inmutable y de solo lectura. Solo el gancho useState () puede asignarle un nuevo valor. No puede hacer esto directamente:



  function FetchUsers() {
    const [users, setUsers] = useState([])

    useEffect(() => {
      const startFetching = async () => {
        const response = await fetch('/users')
        const fetchedUsers = await response.json()

        users = fetchedUsers       // ! users    
        users.push(...fetchedUsers) // ! users 
        setUsers(fetchedUsers)     // !
      }
      startFetching()
    }, [])

    return (
      <ul>
        {users.map(user => <li>{user}</li>)}
      </ul>
    )
  }

      
      





3. Actualización del estado en el componente de clase



Las actualizaciones de estado asincrónicas son comunes para los componentes de la clase.



Consideremos un ejemplo:



import { Component } from 'react';

class DoubleIncreaser extends Component {
  state = {
    count: 0
  };

  render() {
    return (
      <>
        <button onClick={this.doubleIncrease}>
          Double Increase
        </button>
        <div>Count: {this.state.count}</div>
      </>
    );
  }

  doubleIncrease = () => {
    // !
    this.setState(({ count }) => ({
      count: count + 1
    }));
    this.setState(({ count }) => ({
      count: count + 1
    }));

    //  !
    // this.setState({ count: this.state.count + 1 });
    // this.setState({ count: this.state.count + 1 });
  }
}

      
      





Observe el controlador doubleIncrease (): utiliza una función de devolución de llamada para actualizar el estado.



Abra esta demostración y haga clic en el botón. El valor de this.state aumentará a 2.



En los componentes de clase, this.state tampoco se actualiza instantáneamente. Cuando se llama a this.setState (newState), React pospone la actualización de this.state hasta el próximo render.



Entonces this.setState (newState) actualiza this.state de forma asincrónica.



4. Conclusión



El gancho useState () y this.setState () (dentro del componente de la clase) actualizan el valor de la variable y el estado del componente de forma asíncrona.



Recuerde una regla simple: llamar al setter setState (newValue) del gancho useState () (o this.setState ()) no actualiza el estado inmediatamente, sino en la siguiente representación del componente.



¿Ha notado que React ahora solo necesita importarse una vez (en index.js)? Esto ya no es necesario en los componentes.



Gracias por su atención y que tenga un buen día.



All Articles