manejo de estados en React

abril de 2022 (hace 2 años)visitas

Mantener la UI de una aplicación sincronizada con el estado de esta, es algo fundamental pero realmente complejo. Cada vez que cualquier estado cambie, la UI debe de ser actualizada, quizás si nuestra web no tiene mucho dinamismo, esta tarea se puede realizar sin ningún problema, en cambio, si nuestra aplicación comienza a crecer y cada vez es más dinámica, la actualización de estos estados en la UI será practicamente imposible de realizar.

Por esta razón (y por otras menos importantes), existen los frameworks de JS como React, Vue, Angular, etc. que nos permiten manejar estados de forma más sencilla.

¿Qué es el estado de una aplicación?

Es el término que recibe toda la información de la que disponemos en ese momento y se puede acceder (variables, estructuras de datos, etc)

Cómo manejar estados en React

React simplifica mucho el tener un control del estado a través de los hooks useState y useReducer. Ambos permiten actualizar la UI en cuanto nuestra información se actualiza, para explicar su funcionamiento, vamos a utilizar un ejemplo simple como puede ser un contador de likes/dislikes.

const [likes, setLikes] = useState(0)  // Estado de likes
const [dislikes, setDislikes] = useState(0) // Estado de dislikes

return (
    <>
        <p>{`Likes: ${likes}`}</p>
        <button onClick={() => setLikes(likes + 1)}>Like</button>
        <p>{`Dislikes: ${dislikes}`}</p>
        <button onClick={() => setDislikes(dislikes + 1)}>Dislike</button>
    </>
)

En el ejemplo anterior, hemos creado un contador con el que visualizaremos el número de likes y dislikes que tenemos almacenados en nuestros estados (likes y dislikes), también podremos incrementarlos.

Como se puede ver, hemos usado useState, un hook que se introdujo en la versión 16.8, este nos devuelve un array con dos elementos, el primero es la variable de estado y el segundo es una función que nos permite actualizar dicha variable. La variable de estado es inmutable, por lo que no se puede modificar manualmente, para editarla, debemos de usar la función mencionada anteriormente. Este hook recibe un parámetro que es el valor inicial de nuestra variable de estado. El usar la función que nos devuelve el hook conlleva un re-renderizado en la UI para actualizar la información que ha sido modificada.

useState es la manera más comoda para manejar el estado de nuestra aplicación pero quizás no es la mejor opción cuando tenemos una gran cantidad de estados, imaginad que tenemos una aplicación que guarda muchos datos y para cada uno, necesitamos un estado diferente, podríamos crear un useState por cada dato pero no tendría mucho sentido ya que en el futuro no sabríamos a cual se refiere debido a la gran cantidad de estos. Para este tipo de casos, existe useReducer que nos permite manejar estados más complejos, como son lo que tienen una gran cantidad de datos, realmente este hook es una abstracción del reduce de JS.

Para explicar el funcionamiento de useReducer, vamos a utilizar el ejemplo anterior pero usando este hook:

const initialState = {
    likes: 0,
    dislikes: 0
}

const reducer = (state, action) => {
    switch (action.type) {
        case 'LIKE':
            return { ...state, likes: state.likes + 1 }
        case 'DISLIKE':
            return { ...state, dislikes: state.dislikes + 1 }
        default:
            return state
    }
}

const [state, dispatch] = useReducer(reducer, initialState)

return (
    <>
        <p>{`Likes: ${state.likes}`}</p>
        <button onClick={() => dispatch({ type: 'LIKE' })}>Like</button>
        <p>{`Dislikes: ${state.dislikes}`}</p>
        <button onClick={() => dispatch({ type: 'DISLIKE' })}>Dislike</button>
    </>
)

Como se aprecia en el ejemplo, useReducer devuelve un array con dos elementos, el primero es el estado y el segundo es una función que nos permite lanzar acciones, también admite dos parámetros, el primero es la función reductora que ejecutará los cambios en el estado y el segundo es el estado inicial. Esta función reductora recibe como parámetro el estado actual (implícito) y un objeto con la acción que se va a lanzar.

useReducer es algo más complejo de usar que useState pero es más flexible ya que nos permite manejar estados más complejos y con diferentes condiciones. Como siempre, el contexto de nuestra aplicación será el que defina cuál debemos de usar, en la mayoría de los casos useState será el más usado.