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

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

但是像这样更新状态,

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

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


当前回答

如果你想动态设置状态


下面的示例动态设置表单的状态,其中状态中的每个键都是object

 onChange(e:React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
    this.setState({ [e.target.name]: { ...this.state[e.target.name], value: e.target.value } });
  }

其他回答

我非常认真地对待关于创建组件状态的完整副本的问题。说到这里,我强烈推荐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)}

有时候直接回答并不是最好的答案:)

短版:

这段代码

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

应该简化成这样吗

this.state = {
    somePropertyFlag: true
}

长版:

目前你不应该在React中使用嵌套状态。因为React不是面向嵌套状态的,这里提出的所有解决方案看起来都是hack。他们不使用框架,而是与之斗争。他们建议为了分组某些属性的可疑目的而编写不那么清晰的代码。所以它们作为挑战的答案是非常有趣的,但实际上毫无用处。

让我们想象一下下面的状态:

{
    parent: {
        child1: 'value 1',
        child2: 'value 2',
        ...
        child100: 'value 100'
    }
}

如果只改变child1的值会发生什么?React不会重新渲染视图,因为它使用浅比较,它会发现父属性没有改变。顺便说一句,直接改变状态对象通常被认为是一种糟糕的做法。

所以你需要重新创建整个父对象。但在这种情况下,我们会遇到另一个问题。React会认为所有的孩子都改变了他们的价值观,并重新渲染所有的孩子。当然,这对性能没有好处。

通过在shouldComponentUpdate()中编写一些复杂的逻辑仍然可以解决这个问题,但我宁愿在这里停下来,使用简短版本中的简单解决方案。

setInputState((pre)=> ({...pre,[parentKey]: {...pre[parentKey], [childKey]: value}}));

我喜欢这个

用于多个输入控件和动态嵌套名称

<input type="text" name="title" placeholder="add title" onChange={this.handleInputChange} />
<input type="checkbox" name="chkusein" onChange={this.handleInputChange} />
<textarea name="body" id="" cols="30" rows="10" placeholder="add blog content" onChange={this.handleInputChange}></textarea>

代码非常易读

处理程序

handleInputChange = (event) => {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;
        const newState = { ...this.state.someProperty, [name]: value }
        this.setState({ someProperty: newState })
    }

使用箭头函数代替,这应该做的把戏。

setItems((prevState) => {
   prevState.nestedData = newNestedData;
   prevState.nestedData1 = newNestedData1;
});

不要忘记使用箭头函数(prevState) =>{更新js赋值语句…}