Lo importante sobre los hooks de react para tener en cuenta en una entrevista, es potencialmente poder saber y responder tres puntos esenciales:
- Qué son en simples palabras
- Qué problemas resuelven
- Un ejemplo simple de implementación
En esta ocasión, nos toca el manejo de estado.
useState
Qué es?
Este hook es básicamente una forma de declarar una variable que para React va a tener un significado especial:
Cada vez que cambiemos el valor de esta variable, React va a detectar esa actualización y disparar un rerender del componente en el que se encuentra. O sea, volver a crear este componente, volver a pintarlo en el navegador.
Qué problema resuelve?
La idea es tener una manera de que React reaccione ante un cambio que realicemos en una variable. Veamos un ejemplo, sin React:
// Inicializamos una variable que vamos a usar de contador:
let counter = 0
// Actualizamos el valor de esa variable de manera típica:
counter++
Con el ejemplo anterior, efectivamente vamos a aumentar el contador. Pero React no va a estar al tanto de ese cambio. Por lo que si usamos esa variable para mostrar algo en el navegador, el cambio no se va a reflejar.
Ahora, usemos useState:
const [ counter, setCounter ] = useState(0)
Para entender lo que pasa, tenemos que tener bien sabidos dos conceptos de JavaScript:
- Funciones (Documentación).
- Desestructuración de Arrays (Documentación).
Estos dos conceptos nos dejan entender que useState
es básicamente una función que React nos brinda que tiene dos características simples:
- Es una función que puede tomar como parámetro, una de dos cosas:
- Un valor que inicializa la variable
counter
(lo más común) - Una función de inicialización (menos común, más sobre esto luego)
- Un valor que inicializa la variable
- Y a su vez, nos devuelve un array con dos elementos:
- La variable con el valor que nos interesa.
- Una función que sirve para actualizar esa variable.
La forma más simple de usarla es:
setCounter(1)
Esto va a lograr que React vuelva a crear el componente donde estemos usando este hook, y a su vez actualizar el valor de la variable counter
a 1.
Veamos un ejemplo de componente real:
import { useState } from "react";
const MyCounter = () => {
const [counter, setCounter] = useState(0);
return (
<>
<button onClick={() => setCounter(counter + 1)}>Add</button>
<p>{counter}</p>
</>
);
};
Este componente simple cumple con dos tareas:
- Mostrar un botón que al hacer click ejecuta el
setCounter
:-
setCounter
recibe el valor actual decounter
y lo incrementa. - React entiende que hubo un cambio en la UI y dispara un rerender.
-
- Un paragraph que muestra el valor de la variable counter.
Casos especiales
Lo interesante de leer las librerías es que vas descubriendo cosas como por ejemplo, que la función setCounter
acepta un valor para actualizar counter
, pero también se le puede pasar una función.
De esta función podemos recibir un parámetro que es realmente el último valor de counter
. Realmente, al inicio de nuestro camino en React es probable que no nos haga mucha diferencia utilizar un método u otro:
<button onClick={() => setCounter(counter + 1)}>
Add
</button>
// O también
<button onClick={() => setCounter((currentCounter) => currentCounter + 1)}>
Add
</button>
Solamente cuando nos encontramos utilizando este setCounter
en ocasiones o en conjunto con operaciones que lleven un cierto tiempo en completarse, como acciones asíncronas, es cuando necesitamos realmente el último valor actualizado de counter
. Son esos detalles que nos vuelven locos y que terminamos entendiendo de una manera u otra. No hay que pretender entender esto en los primeros momentos del proceso de aprendizaje.
La regla es: recordar que nuestro valor está tardando en actualizarse, o que se está actualizando mal debido a que no estamos tomando el último valor realmente disponible.
Función inicializadora
En otros momentos, necesitamos inicializar el primer estado de nuestro useState
con algún valor que quizás lleve un tiempo en resolver, como una llamada a un endpoint, algún cálculo matemático o incluso leer algo de localStorage. Algo simple pero que lleve un tiempo.
Es muy poco probable tener que usar esto, realmente. Pero useState
también acepta una función que sirve para inicializar solamente una vez y al inicio del renderizado del componente, el valor de nuestro estado. Sería algo así:
const processedUserInfo = getUserComplexInfo()
const [userInfo, setUserInfo] = useState(() => processedUserInfo)
Lo que va a hacer esto es: llenar nuestro userInfo
con la información calculada o procesada una sola vez. Pagamos el precio de la tardanza la primera vez y listo. Luego podemos actualizar y rerenderizar el componente todas las veces siguientes, sin tener que volver a procesar la info de getUserComplexInfo
.
Normalmente es raro utilizar esto, pero existe por una razón. Como regla es bueno medir la performance de tu componente. Realmente si requiere esta manera de inicializar el estado entonces considerar usarlo. Pero optimizar por el mero hecho de optimizar, puede salir más caro de lo que parece.
Por último: si tu componente tiene muchos useState
, es muy probable que necesites usar un useReducer
para simplificar el manejo de estado de tu componente. Así vas a ganar practicidad en la lectura del código y evitar la repetición y malas prácticas.
Si te gustó este contenido y estás iniciando o llevás un tiempo en React y te gustaría que escriba sobre algún otro tema en particular, dejame tu comentario.
Voy a seguir atacando estos temas básicos sobre React de todas maneras.
Gracias por el tiempo!
Seba.
Top comments (0)