Sé que React puede realizar actualizaciones de estado de forma asincrónica y por lotes para la optimización del rendimiento. Por lo tanto, nunca puede confiar en el estado que se actualizará después de haber llamado setState
. Pero se puede confiar Reaccionar a actualizar el estado en el mismo orden que setState
se llama de
- el mismo componente?
- diferentes componentes?
Considere hacer clic en el botón en los siguientes ejemplos:
1. ¿Existe alguna posibilidad de que a sea falso yb sea verdadero para:
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { a: false, b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.setState({ a: true });
this.setState({ b: true });
}
}
2. ¿Existe alguna posibilidad de que a sea falso yb sea verdadero para:
class SuperContainer extends React.Component {
constructor(props) {
super(props);
this.state = { a: false };
}
render() {
return <Container setParentState={this.setState.bind(this)}/>
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.props.setParentState({ a: true });
this.setState({ b: true });
}
}
Tenga en cuenta que estas son simplificaciones extremas de mi caso de uso. Me doy cuenta de que puedo hacer esto de manera diferente, por ejemplo, actualizar ambos parámetros de estado al mismo tiempo en el ejemplo 1, así como realizar la segunda actualización de estado en una devolución de llamada a la primera actualización de estado en el ejemplo 2. Sin embargo, esta no es mi pregunta, y solo me interesa si hay una forma bien definida de que React realice estas actualizaciones de estado, nada más.
Cualquier respuesta respaldada por documentación es muy apreciada.
fuente
Respuestas:
Yo trabajo en React.
TLDR:
Si.
Si.
El orden de las actualizaciones siempre se respeta. Si ves un estado intermedio "entre" o no depende de si estás dentro de un lote o no.
Actualmente (React 16 y anteriores), solo las actualizaciones dentro de los controladores de eventos React se agrupan por defecto . Hay una API inestable para forzar el procesamiento por lotes fuera de los controladores de eventos en casos excepcionales cuando lo necesita.
En futuras versiones (probablemente React 17 y posteriores), React agrupará todas las actualizaciones por defecto para que no tenga que pensar en esto. Como siempre, anunciaremos cualquier cambio al respecto en el blog React y en las notas de la versión.
La clave para entender esto es que no importa cuántas
setState()
llamadas en cuántos componentes realice dentro de un controlador de eventos React , producirán solo una nueva representación al final del evento . Esto es crucial para un buen rendimiento en aplicaciones grandes porque siChild
yParent
cada llamadasetState()
al manejar un evento de clic, no desea volver a renderizar elChild
doble.En ambos ejemplos, las
setState()
llamadas ocurren dentro de un controlador de eventos React. Por lo tanto, siempre se enjuagan al final del evento (y no se ve el estado intermedio).Las actualizaciones siempre se fusionan superficialmente en el orden en que ocurren . Entonces, si la primera actualización es
{a: 10}
, la segunda es{b: 20}
, y la tercera es{a: 30}
, el estado representado será{a: 30, b: 20}
. La actualización más reciente de la misma clave de estado (por ejemplo, comoa
en mi ejemplo) siempre "gana".El
this.state
objeto se actualiza cuando volvemos a representar la interfaz de usuario al final del lote. Entonces, si necesita actualizar el estado en función de un estado anterior (como incrementar un contador), debe usar lasetState(fn)
versión funcional que le proporciona el estado anterior, en lugar de leerthis.state
. Si tienes curiosidad sobre el razonamiento de esto, lo expliqué en profundidad en este comentario .En su ejemplo, no veríamos el "estado intermedio" porque estamos dentro de un controlador de eventos React donde se habilita el procesamiento por lotes (porque React "sabe" cuando salimos de ese evento).
Sin embargo, tanto en React 16 como en versiones anteriores, todavía no hay lotes por defecto fuera de los controladores de eventos React . Entonces, si en su ejemplo tuviéramos un controlador de respuesta AJAX en lugar de
handleClick
, cada unosetState()
se procesaría de inmediato cuando ocurriera. En este caso, sí, usted podría ver un estado intermedio:Sabemos que es inconveniente que el comportamiento sea diferente dependiendo de si estás en un controlador de eventos o no . Esto cambiará en una futura versión de React que agrupará todas las actualizaciones por defecto (y proporcionará una API opcional para eliminar los cambios sincrónicamente). Hasta que cambiemos el comportamiento predeterminado (potencialmente en React 17), hay una API que puede usar para forzar el procesamiento por lotes :
Los controladores de eventos de Reaccionar internamente se están envolviendo, por
unstable_batchedUpdates
lo que están agrupados por defecto. Tenga en cuenta que ajustar una actualizaciónunstable_batchedUpdates
dos veces no tiene ningún efecto. Las actualizaciones se vacían cuando salimos de launstable_batchedUpdates
llamada más externa .Esa API es "inestable" en el sentido de que la eliminaremos cuando el procesamiento por lotes ya esté habilitado de forma predeterminada. Sin embargo, no lo eliminaremos en una versión menor, por lo que puede confiar en él de forma segura hasta React 17 si necesita forzar el procesamiento por lotes en algunos casos fuera de los controladores de eventos React.
En resumen, este es un tema confuso porque React solo se agrupa dentro de los controladores de eventos de forma predeterminada. Esto cambiará en futuras versiones, y el comportamiento será más directo que entonces. Pero la solución no es agrupar menos , sino agrupar más por defecto. Eso es lo que vamos a hacer.
fuente
obj.a = true; obj.b = true
. Ej. ) Y, al final, simplemente hacerthis.setState(obj)
. Esto es seguro independientemente de si está dentro de un controlador de eventos o no. Podría ser un buen truco si a menudo te encuentras cometiendo el error de establecer el estado varias veces fuera de los controladores de eventos.componentDidUpdate
y otras devoluciones de llamada del ciclo de vida a partir de React 16? ¡Gracias por adelantado!Esta es realmente una pregunta bastante interesante, pero la respuesta no debería ser demasiado complicada. Existe este gran artículo sobre medio que tiene una respuesta.
1) Si haces esto
No creo que haya una situación en la que
a
se debatrue
yb
se debafalse
al procesamiento por lotes .Sin embargo, si
b
depende de,a
entonces podría haber una situación en la que no obtendrías el estado esperado.Después de que se procesen todas las llamadas anteriores,
this.state.value
serán 1, no 3 como cabría esperar.Esto se menciona en el artículo:
setState accepts a function as its parameter
Esto nos dará
this.state.value === 3
fuente
this.state.value
se actualiza tanto en los controladores de eventos (dondesetState
está agrupado) como en las devoluciones de llamada AJAX (donde nosetState
está agrupado)? En los controladores de eventos, usaría el para siempre estar seguro de que actualizo el estado usando el estado actualizado actualmente proporcionado por la función. ¿Debo usar una función de actualización dentro del código de la devolución de llamada AJAX incluso si sé que no está en lote? ¿Podría aclarar el uso de una devolución de llamada AJAX con o sin el uso de una función de actualización? ¡Gracias!updater function
setState
setState
setState
serían ejecutados pero el último ganaría.Se pueden agrupar varias llamadas durante el mismo ciclo. Por ejemplo, si intenta incrementar la cantidad de un artículo más de una vez en el mismo ciclo, eso resultará en el equivalente de:
https://reactjs.org/docs/react-component.html
fuente
como en doc
preformará el cambio como en la cola ( FIFO : Primero en entrar, primero en salir) la primera llamada será la primera en preformarse
fuente