我试图通过使用这样的嵌套属性来组织我的状态:

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

但是像这样更新状态,

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

是行不通的。怎样才能正确地做到这一点呢?


当前回答

stateUpdate = () => {
    let obj = this.state;
    if(this.props.v12_data.values.email) {
      obj.obj_v12.Customer.EmailAddress = this.props.v12_data.values.email
    }
    this.setState(obj)
}

其他回答

我非常认真地对待关于创建组件状态的完整副本的问题。说到这里,我强烈推荐Immer。

import produce from 'immer';

<Input
  value={this.state.form.username}
  onChange={e => produce(this.state, s => { s.form.username = e.target.value }) } />

这应该适用于React。PureComponent(即通过React进行浅状态比较),因为Immer巧妙地使用代理对象来有效地复制任意深度状态树。Immer也比Immutability Helper等库更加类型安全,是Javascript和Typescript用户的理想选择。


Typescript实用函数

function setStateDeep<S>(comp: React.Component<any, S, any>, fn: (s: 
Draft<Readonly<S>>) => any) {
  comp.setState(produce(comp.state, s => { fn(s); }))
}

onChange={e => setStateDeep(this, s => s.form.username = e.target.value)}

我发现这对我很有用,在我的案例中有一个项目表单,例如,你有一个id和一个名称,我宁愿为一个嵌套的项目维护状态。

return (
  <div>
      <h2>Project Details</h2>
      <form>
        <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
        <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
      </form> 
  </div>
)

让我知道!

我用了这个方法。

如果你有一个这样的嵌套状态:

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

你可以声明handleChange函数来复制当前状态并重新赋值

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);
  }

这里是带有事件侦听器的HTML

<input type="text" onChange={this.handleChange} " name="friendName" />
setInputState((pre)=> ({...pre,[parentKey]: {...pre[parentKey], [childKey]: value}}));

我喜欢这个

为了让事情变得通用,我研究了@ShubhamKhatri和@Qwerty的答案。

状态对象

this.state = {
  name: '',
  grandParent: {
    parent1: {
      child: ''
    },
    parent2: {
      child: ''
    }
  }
};

输入控件

<input
  value={this.state.name}
  onChange={this.updateState}
  type="text"
  name="name"
/>
<input
  value={this.state.grandParent.parent1.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent1.child"
/>
<input
  value={this.state.grandParent.parent2.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent2.child"
/>

updateState方法

setState作为@ShubhamKhatri的答案

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const oldstate = this.state;
  const newstate = { ...oldstate };
  let newStateLevel = newstate;
  let oldStateLevel = oldstate;

  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      newStateLevel[path[i]] = event.target.value;
    } else {
      newStateLevel[path[i]] = { ...oldStateLevel[path[i]] };
      oldStateLevel = oldStateLevel[path[i]];
      newStateLevel = newStateLevel[path[i]];
    }
  }
  this.setState(newstate);
}

setState作为@Qwerty的答案

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const state = { ...this.state };
  let ref = state;
  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      ref[path[i]] = event.target.value;
    } else {
      ref = ref[path[i]];
    }
  }
  this.setState(state);
}

注意:上述方法不适用于数组