Los componentes de React pueden, y a menudo lo hacen, tener Expresar. El estado puede ser cualquier cosa, pero piense en cosas como si un usuario está conectado 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á activa.
Reaccione los componentes con la interfaz de usuario de procesamiento de estado en función de ese estado. Cuando cambia el estado de los componentes, también cambia la interfaz de usuario del componente.
Eso hace que sea importante comprender cuándo y cómo cambiar el estado de su componente. Al final de este tutorial, debe saber cómo setState
funciona, y ser capaz de evitar los errores comunes que muchos de nosotros encontramos cuando aprendemos 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 setState()
. El objeto contiene la parte del estado que queremos actualizar que, en este caso, es el valor de searchTerm
. React toma este valor y lo fusiona con el objeto que lo necesita. Es como el Search
El componente pregunta qué debe usar para el valor de searchTerm
y setState()
responde con una respuesta.
Básicamente, esto está iniciando un proceso que React llama reconciliación. El proceso de reconciliación es la forma en que React actualiza el DOM, realizando cambios en el componente según el cambio de estado. Cuando la solicitud de setState()
se activa, React crea un nuevo árbol que contiene los elementos reactivos en el componente (junto con el estado actualizado). Este árbol se utiliza para averiguar cómo Search
La interfaz de usuario del componente debería cambiar en respuesta al cambio de estado comparándola 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 flujo:
- Tenemos un componente de búsqueda que muestra un término de búsqueda.
- Ese término de búsqueda está vacío actualmente
- El usuario envía un término de búsqueda
- Ese término es capturado y almacenado por
setState
como valor - Se lleva a cabo la reconciliación y React nota el cambio de valor
- React 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:
// old
<div>
<Search />
</div>
// new
<span>
<Search />
</span>
Todo <div>
las etiquetas se convierten <span>
Como resultado, se actualizarán las etiquetas y todo el árbol de componentes.
La regla general es nunca mutar el estado directamente. Siempre usa 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 this
this.state = {
searchTerm: event.target.value
}
Pasando una función a `setState ()`
Para demostrar más esta idea, creemos un contador simple que aumente y disminuya al hacer clic.
Vea el Pen setState Pen de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Registremos el componente y definamos 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 reduce el recuento en 1 en cada clic.
Pero, ¿y si quisiéramos incrementar o disminuir en 3 en su lugar? Podríamos intentar llamar setState()
tres veces en el handleDecrement
y handleIncrement
funciona así:
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 está codificando en casa, es posible que se sorprenda al encontrar 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 los datos que se copian del origen al destino tienen todas las mismas claves, como en nuestro ejemplo, el último objeto gana. Aquí hay una versión más simple de cómo Object.assign()
obras;
let count = 3
const 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 repita tres veces, solo ocurre una vez. Esto se puede solucionar pasando una función a setState()
. Al igual que pasa objetos a setState()
, también puede pasar funciones, y esa es la forma de salir de la situación anterior.
Si editamos el handleIncrement
función para verse 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 recuento tres veces con un solo clic.
En este caso, en lugar de fusionar, React pone en cola las llamadas a la función en el orden en que se realizan y actualiza el estado completo en el que se hizo. Esto actualiza el estado de la cuenta a 3 en lugar de 1.
Acceder al estado anterior usando el actualizador
Al crear aplicaciones React, hay ocasiones en las que querrá calcular el estado en función del estado anterior del componente. No siempre puedes confiar this.state
para mantener el estado correcto inmediatamente después de llamar setState()
, ya que siempre es igual al estado representado en la pantalla.
Volvamos a nuestro contraejemplo para ver cómo funciona. Digamos que tenemos una función que reduce nuestra cuenta 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()
La 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 el componente se ha vuelto a renderizar. La solución es utilizar un actualizador. Un actualizador le permite acceder al estado actual y utilizarlo inmediatamente para actualizar otros elementos. Entonces el changeCount()
La 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
están construidos unos sobre otros 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 setState()
.
Terminando
Al trabajar con setState()
, estas son las cosas más importantes que debe saber:
- La actualización a un estado de componente debe realizarse usando
setState()
- Puede pasar un objeto o una función a
setState()
- Pase una función cuando pueda para actualizar el estado varias veces
- No dependa de esto, indique inmediatamente después de llamar
setState()
y utilice la función de actualización en su lugar.