Pregunta Cómo actualizar las propiedades de estado anidado en React


Estoy tratando de organizar mi estado usando propiedades anidadas como esta:

this.state = {
   someProperty: {
      flag:true
   }
}

Pero actualizando el estado así,

this.setState({ someProperty.flag: false });

no funciona ¿Cómo se puede hacer esto correctamente?


74
2018-03-27 07:51


origen


Respuestas:


A fin de que setState para un objeto anidado puede seguir el enfoque a continuación, ya que creo que setState no maneja las actualizaciones anidadas.

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

La idea es crear un objeto ficticio realizar operaciones en él y luego reemplazar el estado del componente con el objeto actualizado

Ahora, el operador de difusión crea solo una copia anidada de nivel del objeto. Si su estado está muy anidado como:

this.state = {
   someProperty: {
      someOtherProperty: {
          anotherProperty: {
             flag: true
          }
          ..
      }
      ...
   }
   ...
}

Podría establecer State usando el operador de propagación en cada nivel como

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))

Sin embargo, la sintaxis anterior se pone cada vez más fea a medida que el estado se anida cada vez más y, por lo tanto, te recomiendo usar immutability-helper paquete para actualizar el estado.

Vea esta respuesta sobre cómo actualizar el estado con immutability helper.


114
2018-03-27 08:25



Para escribirlo en una linea

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

38
2017-08-09 22:07



Si está utilizando ES2015, tiene acceso a Object.assign. Puede usarlo de la siguiente manera para actualizar un objeto anidado.

this.setState({
  someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});

Combina las propiedades actualizadas con las existentes y utiliza el objeto devuelto para actualizar el estado.

Editar: se agregó un objeto vacío como destino a la función de asignación para asegurarse de que el estado no se mute directamente, como señaló carkod.


15
2017-10-07 19:20



Aquí hay una variación de la primera respuesta dada en este hilo que no requiere paquetes adicionales, bibliotecas o funciones especiales.

state = {
  someProperty: {
    flag: 'string'
  }
}

handleChange = (value) => {
  const newState = {...this.state.someProperty, flag: value}
  this.setState({ someProperty: newState })
}

Para establecer el estado de un campo anidado específico, ha establecido el objeto completo. Hice esto creando una variable, newState y difundir los contenidos del estado actual en él primero usando el ES2015 operador de propagación. Entonces, reemplacé el valor de this.state.flag con el nuevo valor (desde que establecí flag: value  después Extiendo el estado actual en el objeto, el flag campo en el estado actual es anulado). Entonces, simplemente configuré el estado de someProperty para mi newState objeto.


5
2017-11-29 17:10



Hay muchas bibliotecas para ayudar con esto. Por ejemplo, usando inmutabilidad-ayudante:

import update from 'immutability-helper';

const newState = update(this.state, {
  someProperty: {flag: {$set: false}}
};
this.setState(newState);

O usando lodash / fp:

import {merge} from 'lodash/fp';
const newState = merge(this.state, {
  someProperty: {flag: false}
});

5
2018-05-19 08:15



el mejor de todos

Hay otro corta forma de actualizar cualquier propiedad anidada

this.setState(state => {
  state.nested.flag = false
  state.another.deep.prop = true
  return state
})

En una linea

this.setState(state => (state.nested.flag = false, state))

Por supuesto, esto está abusando de algunos principios básicos, ya que state debe ser de solo lectura, pero como está descartando inmediatamente el estado anterior y reemplazándolo con un nuevo estado, está completamente bien.

Advertencia

Aunque el componente que contiene el estado será actualizar y rerender adecuadamente (excepto esto gotcha), los accesorios serán fallar para propagar a los niños (ver el comentario del maestro espía a continuación). Solo use esta técnica si sabe lo que está haciendo.

Por ejemplo, puede pasar un pilar plano modificado que se actualiza y pasa fácilmente.

render(
  //some complex render with your nested state
  <ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)

Ahora, aunque la referencia para complexNestedProp no cambió (shouldComponentUpdate)

this.props.complexNestedProp === nextProps.complexNestedProp

el componente será rerender cada vez que se actualicen los componentes de los padres, que es el caso después de llamar this.setState o this.forceUpdate en el padre


4
2018-05-03 07:50



Usé esta solución.

Si tiene un estado anidado como este:

   this.state = {
          formInputs:{
            friendName:{
              value:'',
              isValid:false,
              errorMsg:''
            },
            friendEmail:{
              value:'',
              isValid:false,
              errorMsg:''
            }
}

puede declarar la función handleChange que copia el estado actual y lo reasigna con los valores modificados

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

aquí el html con el oyente del evento

<input type="text" onChange={this.handleChange} " name="friendName" />

2
2018-03-06 09:40