
Entendiendo la reacción `setState`

Los componentes de React pueden tener, ya a menudo tienen, estado . El estado puede ser cualquier cosa, pero piensa en cosas como si un usuario inició sesión o no y muestra el nombre de usuario correcto según la cuenta que esté activa. O una variedad de publicaciones de blog. O si un modal está abierto o no y qué pestaña dentro de él está activada.
Los componentes de React con el estado representan la interfaz de usuario según ese estado. Cuando el estado de los componentes cambia, también lo hace la interfaz de usuario del componente.
Por eso es importante comprender cuándo y cómo cambiar el estado de su componente. Al final de este tutorial, deberías saber cómo setState
funciona y poder evitar errores comunes que muchos de nosotros encontramos al aprender React.
Funcionamiento de `setState()`
setState()
es la única forma legítima de actualizar el estado después de la configuración del estado inicial. Digamos que tenemos un componente de búsqueda y queremos mostrar el término de búsqueda que envía un usuario.
Aquí está la configuración:
import React, { Component } from 'react'class Search extends Component { constructor(props) { super(props) state = { searchTerm: '' } }}
Pasamos una cadena vacía como valor y, para actualizar el estado de searchTerm
, tenemos que llamar setState()
.
setState({ searchTerm: event.target.value })
Aquí le estamos pasando un objeto a setState()
. El objeto contiene la parte del estado que queremos actualizar que, en este caso, es el valor de searchTerm
. Reacciona toma este valor y lo fusiona con el objeto que lo necesita. Es algo así como si el Search
componente preguntara qué debería usar como valor searchTerm
y setState()
respondería con una respuesta.
Básicamente, esto inicia un proceso llamado React reconciliación. El proceso de reconciliación es la forma en que React actualiza el DOM, realizando cambios en el componente en función del cambio de estado. Cuando se activa la solicitud setState()
, React crea un nuevo árbol que contiene los elementos reactivos en el componente (junto con el estado actualizado). Este árbol se utiliza para determinar cómo debería cambiar la interfaz de usuarioSearch
del componente en respuesta al cambio de estado comparándolo con los elementos del árbol anterior. React sabe qué cambios implementará y solo actualizará las partes del DOM cuando sea necesario. Por eso React es rápido.
Parece mucho, pero para resumir el artículo:
- Tenemos un componente de búsqueda que muestra un término de búsqueda.
- Ese término de búsqueda está actualmente vacío.
- El usuario envía un término de búsqueda.
- Ese término se captura y almacena
setState
como un valor. - Se produce la reconciliación y React nota el cambio de valor.
- React le indica al componente de búsqueda que actualice el valor y el término de búsqueda se fusiona en
El proceso de reconciliación no cambia necesariamente todo el árbol, excepto en una situación en la que la raíz del árbol cambia de esta manera:
// olddiv Search //div// newspan Search //span
Todas div
las etiquetas se convierten en span
etiquetas y todo el árbol de componentes se actualizará como resultado.
La regla general nunca es mutar el estado directamente. Úselo siempre setState()
para cambiar de estado. Modificar el estado directamente, como el fragmento a continuación, no hará que el componente se vuelva a renderizar.
// do not do thisthis.state = { searchTerm: event.target.value}
Pasar una función a `setState()`
Para demostrar aún más esta idea, creemos un contador simple que aumenta y disminuye al hacer clic.
Registraremos el componente y definimos el marcado para la interfaz de usuario :
class App extends React.Component {state = { count: 0 }handleIncrement = () = { this.setState({ count: this.state.count + 1 })}handleDecrement = () = { this.setState({ count: this.state.count - 1 })} render() { return ( div div {this.state.count} /div button onClick={this.handleIncrement}Increment by 1/button button onClick={this.handleDecrement}Decrement by 1/button /div ) }}
En este punto, el contador simplemente incrementa o disminuye el recuento en 1 con cada clic.
Pero, ¿qué pasaría si en su lugar quisiéramos incrementar o disminuir en 3? Podríamos intentar llamar setState()
tres veces a funciones handleDecrement
y handleIncrement
como esta:
handleIncrement = () = { this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 })}handleDecrement = () = { this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 })}
Si lo codificas en casa, te sorprenderá descubrir que eso no funciona.
El fragmento de código anterior es equivalente a:
Object.assign( {}, { count: this.state.count + 1 }, { count: this.state.count + 1 }, { count: this.state.count + 1 },)
Object.assign()
se utiliza para copiar datos de un objeto de origen a un objeto de destino. Si todos los datos que se copian del origen al destino tienen las mismas claves, como en nuestro ejemplo, el último objeto gana. Aquí hay una versión más sencilla de cómo Object.assign()
funciona;
let count = 3const object = Object.assign({}, {count: count + 1}, {count: count + 2}, {count: count + 3});console.log(object);// output: Object { count: 6 }
Entonces, en lugar de que la llamada se realice tres veces, se realizará solo una vez. Esto se puede solucionar pasando una función a setState()
. Así como pasan objetos a setState()
, también pueden pasar funciones, y esa es la forma de salir de la situación anterior.
Si editamos la handleIncrement
función para que se vea así:
handleIncrement = () = { this.setState((prevState) = ({ count: prevState.count + 1 })) this.setState((prevState) = ({ count: prevState.count + 1 })) this.setState((prevState) = ({ count: prevState.count + 1 }))}
…ahora podemos incrementar el conteo tres veces con un solo clic.
En este caso, en lugar de fusionarse, React pone en cola las llamadas a funciones en el orden en que se realizan y actualiza todo el estado en el que se realizan. Esto actualiza el estado del contador a 3 en lugar de 1.
Acceder al estado anterior mediante el actualizador
Al crear aplicaciones React, hay ocasiones en las que querrás calcular el estado en función del estado anterior del componente. No siempre puedes confiar this.state
en mantener el estado correcto inmediatamente después de llamar setState()
, ya que siempre es igual al estado que se muestra en la pantalla.
Volvamos a nuestro contraejemplo para ver cómo funciona. Digamos que tenemos una función que disminuye nuestro recuento en 1. Esta función se ve así:
changeCount = () = { this.setState({ count: this.state.count - 1})}
Lo que queremos es la capacidad de disminuir en 3. La changeCount()
función se llama tres veces en una función que maneja el evento de clic, como esta.
handleDecrement = () = { this.changeCount() this.changeCount() this.changeCount()}
Cada vez que se hace clic en el botón para disminuir, el recuento disminuirá en 1 en lugar de 3. Esto se debe a que this.state.count
no se actualiza hasta que se haya vuelto a renderizar el componente. La solución es utilizar un actualizador. Un actualizador le permite acceder al estado actual y utilizarlo inmediatamente para actualizar otros elementos. Entonces la changeCount()
función se verá así.
changeCount = () = { this.setState((prevState) = { return { count: prevState.count - 1} })}
Ahora no dependemos del resultado de this.state
. Los estados de count
se basan entre sí para que podamos acceder al estado correcto que cambia con cada llamada a changeCount()
.
setState()
debe tratarse de forma asincrónica; en otras palabras, no siempre espere que el estado haya cambiado después de llamar a setState()
.
terminando
Cuando trabajas con setState()
, estas son las cosas más importantes que debes saber:
- La actualización del estado de un componente debe realizarse mediante
setState()
- Puedes pasar un objeto o una función a
setState()
- Pase una función cuando pueda actualizar el estado varias veces
- No dependa de this.state inmediatamente después de llamar
setState()
y utilice la función de actualización.
Deja una respuesta