Por Jorge Aguiar Martín y Adrián Ferrera González
Hoy te traemos una píldora de conocimiento de React, que descubrimos en base a un problema que tuvimos en un proyecto en el que teníamos concurrencia en el frontend.
En nuestro caso, teníamos un estado dentro de un contexto, del que varias pantallas necesitaban obtener información y en el cual varios “procesos” realizaban una actualización simultánea del mismo. El problema está en que, si dichos procesos hacen la actualización del estado a la vez, podemos tener inconsistencias ya que necesitamos el estado anterior para no sobreescribir con información errónea el mismo.
Por aquí te dejamos un repo en el que, si lo ejecutamos y le damos al botón de start, veremos la inconsistencia que se genera en el estado al intentar hacer la actualización de manera convencional, incluso si considerásemos el estado anterior dentro del setState
. También está el ejemplo al lado de como sería, adoptando la solución que más abajo mencionamos.
El principal causante de esto es que React ha diseñado los setState de manera asíncrona, es decir, es un evento que se hace trigger en un momento dado, pero no podemos saber en que momento se ha lanzado. Por tanto, no tenemos certeza de que el “estado anterior” no se pueda modificar desde el momento que se lanza el evento de seteo, hasta que finalmente se modifica el mismo.
Como el problema es que los seteos son asíncronos, debemos tener algún mecanismo por el cual podamos hacer que, o bien sean síncronos, o dependan unos de otros.
Sin conocer a fondo React, la primera solución que se nos viene a la cabeza es usar dentro del setState
el valor del estado que tenemos para sobreescribir el mismo. Nos daríamos cuenta enseguida de que esto realmente no funciona.
const [stateValue, setStateValue] = React.useState({})
// Esto NO nos garantiza que el valor del estado sea el "previo"
const updateStateWithoutPreviousStateValue = (newStateValue) => {
setStateValue({ ...stateValue, ...newStateValue })
}
Tras hacer búsqueda intensiva en Internet, llegamos a la documentación oficial de React, en la que existe la manera de que dicha modificación de un estado dependa siempre del estado anterior, (no el que nosotros tenemos en la variable expuesta, sino del último seteo que se ha hecho del mismo). Es tan sencillo como usar el mismo setState
de antes, pero pasándole como argumento una función que tendrá como parámetro el que será el estado anterior, para poder depender de él.
const [stateValue, setStateValue] = React.useState({})
// De esta manera SI garantizamos que estamos cogiendo el valor
// "previo" del estado
const updateStateBasedOnPreviousStateValue = (newStateValue) => {
setStateValue((previousStateValue) => {
return { ...previousStateValue, ...newStateValue }
})
}
Finalmente, este pequeño reto nos ha hecho comprender mejor el funcionamiento de React, así como enfrentarnos a una situación un tanto diferente y aprender de ella.
¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.
Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?
Pero espera 🖐 que tenemos un conflicto interno. A nosotros las newsletter nos parecen 💩👎👹 Por eso hemos creado la LEAN LISTA, la primera lista zen, disfrutona y que suena a rock y reggaeton del sector de la programación. Todos hemos recibido newsletters por encima de nuestras posibilidades 😅 por eso este es el compromiso de la Lean Lista