Tengo el siguiente estado:
this.setState({ selected: { id: 1, name: 'Foobar' } });
Luego actualizo el estado:
this.setState({ selected: { name: 'Barfoo' }});
Como setState
se supone que debe fusionarse, esperaría que fuera:
{ selected: { id: 1, name: 'Barfoo' } };
Pero en cambio, se come la identificación y el estado es:
{ selected: { name: 'Barfoo' } };
¿Es este comportamiento esperado y cuál es la solución para actualizar solo una propiedad de un objeto de estado anidado?
fuente
this.setState({ selected: { ...this.state.selected, name: 'barfoo' } })
que se traduce athis.setState({ selected: _extends({}, this.state.selected, { name: 'barfoo' }) });
underscore
/lodash
. Gíralo en su propia respuesta, por favor.this.state
no está necesariamente actualizado . Puede obtener resultados inesperados utilizando el método extendido. Pasar una función de actualización asetState
es la solución correcta.Los ayudantes de inmutabilidad se agregaron recientemente a React.addons, por lo que con eso, ahora puede hacer algo como:
Documentación de ayuda de inmutabilidad .
fuente
React.addons.update()
método está en desuso, pero la biblioteca de reemplazo github.com/kolodny/immutability-helper contiene unaupdate()
función equivalente .Dado que muchas de las respuestas utilizan el estado actual como base para fusionarse en nuevos datos, quería señalar que esto puede romperse. Los cambios de estado se ponen en cola y no modifican inmediatamente el objeto de estado de un componente. Hacer referencia a los datos de estado antes de que se haya procesado la cola, por lo tanto, le dará datos obsoletos que no reflejan los cambios pendientes que realizó en setState. De los documentos:
Esto significa que el uso del estado "actual" como referencia en llamadas posteriores a setState no es confiable. Por ejemplo:
Si necesita usar el estado actual (por ejemplo, para combinar datos en un objeto anidado), setState acepta alternativamente una función como argumento en lugar de un objeto; la función se llama después de cualquier actualización previa de estado, y pasa el estado como argumento, por lo que esto puede usarse para realizar cambios atómicos garantizados para respetar los cambios anteriores.
fuente
this.state
, que puede ser obsoleto (o más bien, pendiente de actualización en cola) cuando accede a él.No quería instalar otra biblioteca, así que aquí hay otra solución.
En vez de:
Haz esto en su lugar:
O, gracias a @ icc97 en los comentarios, aún más sucinta pero posiblemente menos legible:
Además, para ser claros, esta respuesta no viola ninguna de las preocupaciones que @bgannonpl mencionó anteriormente.
fuente
this.setState({ selected: Object.assign(this.state.selected, { name: "Barfoo" }));
Object.assign(a, b)
toma atributosb
, los inserta / los sobrescribea
y luego los devuelvea
. Las personas reaccionan se vuelven optimistas si modificas el estado directamente.{}
como primer argumento:this.setState({ selected: Object.assign({}, this.state.selected, { name: "Barfoo" }) });
. Esto no muta el estado original.Preservar el estado anterior basado en la respuesta @bgannonpl:
Ejemplo de Lodash :
Para verificar que funcionó correctamente, puede usar la devolución de llamada de la función del segundo parámetro:
Solía
merge
porqueextend
descarta las otras propiedades de lo contrario.Ejemplo de reacción de inmutabilidad :
fuente
Mi solución para este tipo de situación es usar, como otra respuesta señalada, los ayudantes de Inmutabilidad .
Dado que establecer el estado en profundidad es una situación común, he creado el siguiente mixin:
Este mixin está incluido en la mayoría de mis componentes y generalmente no uso
setState
directamente.Con este mixin, todo lo que necesita hacer para lograr el efecto deseado es llamar a la función
setStateinDepth
de la siguiente manera:Para más información:
setStateinDepth
ver la documentación de Immutability Helpers .fuente
this.state.test.two
seguirá estando allí después de actualizarthis.state.test.one
usandosetStateInDepth({test: {one: {$set: 'new-value'}}})
. Utilizo este código en todos mis componentes para evitar lasetState
función limitada de React .this.state.test
como una matriz. Cambiando a Objetos, lo resolvió.Estoy usando clases es6, y terminé con varios objetos complejos en mi estado superior e intentaba hacer que mi componente principal fuera más modular, así que creé un contenedor de clase simple para mantener el estado en el componente superior pero permitir más lógica local .
La clase wrapper toma una función como su constructor que establece una propiedad en el estado del componente principal.
Luego, para cada propiedad compleja en el estado superior, creo una clase StateWrapped. Puede establecer los accesorios predeterminados en el constructor aquí y se establecerán cuando se inicialice la clase, puede consultar el estado local para los valores y establecer el estado local, consultar las funciones locales y hacer que pase por la cadena:
Entonces, mi componente de nivel superior solo necesita que el constructor establezca cada clase en su propiedad de estado de nivel superior, un render simple y cualquier función que comunique componentes cruzados.
Parece que funciona bastante bien para mis propósitos, tenga en cuenta que no puede cambiar el estado de las propiedades que asigna a los componentes encapsulados en el componente de nivel superior ya que cada componente encapsulado sigue su propio estado pero actualiza el estado en el componente superior Cada vez que cambia.
fuente
A partir de ahora,
de acuerdo con la documentación https://reactjs.org/docs/react-component.html#setstate , utilizando:
fuente
Solución
Editar: Esta solución solía usar sintaxis de propagación . El objetivo era hacer un objeto sin referencias
prevState
, para queprevState
no se modificara. Pero en mi uso,prevState
parecía estar modificado a veces. Entonces, para una clonación perfecta sin efectos secundarios, ahora convertimosprevState
a JSON y luego nuevamente. (La inspiración para usar JSON vino de MDN ).Recuerda:
setState(prevState => stateChange)
Pasos
state
que desea cambiarLos pasos 3 y 4 se pueden combinar en una línea.
Ejemplo
Ejemplo simplificado:
Esto sigue las pautas de React muy bien. Basado en la respuesta de eicksl a una pregunta similar.
fuente
Solución ES6
Establecemos el estado inicialmente
Estamos cambiando una propiedad en algún nivel del objeto de estado:
fuente
El estado de reacción no realiza la fusión recursiva
setState
mientras espera que no haya actualizaciones de miembros de estado en el lugar al mismo tiempo. Debe copiar los objetos / matrices adjuntos usted mismo (con array.slice u Object.assign) o usar la biblioteca dedicada.Como éste. NestedLink admite directamente el manejo del estado React compuesto.
Además, el enlace al
selected
oselected.name
se puede pasar a todas partes como un solo accesorio y modificarse allí conset
.fuente
¿Has establecido el estado inicial?
Usaré algunos de mi propio código, por ejemplo:
En una aplicación en la que estoy trabajando, así es como he estado configurando y usando el estado. Creo
setState
que puedes editar los estados que quieras individualmente. Lo he estado llamando así:Tenga en cuenta que debe establecer el estado dentro de la
React.createClass
función que llamógetInitialState
fuente
Yo uso el tmp var para cambiar.
fuente
let original = {a:1}; let tmp = original; tmp.a = 5; // original is now === Object {a: 5}
No hagas esto, incluso si aún no te ha dado problemas.