我试图通过使用这样的嵌套属性来组织我的状态:
this.state = {
someProperty: {
flag:true
}
}
但是像这样更新状态,
this.setState({ someProperty.flag: false });
是行不通的。怎样才能正确地做到这一点呢?
我试图通过使用这样的嵌套属性来组织我的状态:
this.state = {
someProperty: {
flag:true
}
}
但是像这样更新状态,
this.setState({ someProperty.flag: false });
是行不通的。怎样才能正确地做到这一点呢?
当前回答
我们使用Immer https://github.com/mweststrate/immer来处理这类问题。
只是在我们的一个组件中替换了这段代码
this.setState(prevState => ({
...prevState,
preferences: {
...prevState.preferences,
[key]: newValue
}
}));
用这个
import produce from 'immer';
this.setState(produce(draft => {
draft.preferences[key] = newValue;
}));
使用immer,您可以将您的状态作为“普通对象”处理。 神奇的事情发生在代理对象的幕后。
其他回答
我发现这对我很有用,在我的案例中有一个项目表单,例如,你有一个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.hugeNestedObject = hugeNestedObject;
this.state.anotherHugeNestedObject = anotherHugeNestedObject;
this.setState({})
然而,React本身应该迭代思想嵌套对象,并相应地更新状态和DOM。
我知道这是一个老问题,但仍然想分享我是如何做到这一点的。假设构造函数中的状态是这样的:
constructor(props) {
super(props);
this.state = {
loading: false,
user: {
email: ""
},
organization: {
name: ""
}
};
this.handleChange = this.handleChange.bind(this);
}
我的handleChange函数是这样的:
handleChange(e) {
const names = e.target.name.split(".");
const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
this.setState((state) => {
state[names[0]][names[1]] = value;
return {[names[0]]: state[names[0]]};
});
}
并确保你的输入相应的名称:
<input
type="text"
name="user.email"
onChange={this.handleChange}
value={this.state.user.firstName}
placeholder="Email Address"
/>
<input
type="text"
name="organization.name"
onChange={this.handleChange}
value={this.state.organization.name}
placeholder="Organization Name"
/>
这是第一个答案的变体,不需要任何额外的包、库或特殊函数。
state = {
someProperty: {
flag: 'string'
}
}
handleChange = (value) => {
const newState = {...this.state.someProperty, flag: value}
this.setState({ someProperty: newState })
}
为了设置特定嵌套字段的状态,您已经设置了整个对象。为此,我创建了一个变量newState,并首先使用ES2015扩展操作符将当前状态的内容扩散到该变量中。然后,我用新值替换了this.state.flag的值(因为我在将当前状态扩展到对象后设置了flag: value,所以当前状态下的flag字段将被覆盖)。然后,我简单地将someProperty的状态设置为newState对象。
下面是一个完整的例子,使用嵌套状态(一层)和这个答案中的解决方案,对于一个实现为类的组件:
class CaveEditModal extends React.Component {
// ...
constructor(props, context) {
super(props);
this.state = {
tabValue: '1',
isModalOpen: this.props.isModalOpen,
// ...
caveData: {
latitude: 1,
longitude: 2
}
};
// ...
const updateNestedFieldEvent = fullKey => ev => {
var [parentProperty, _key] = fullKey.split(".", 2);
this.setState({[parentProperty]: { ...this.state[parentProperty], [_key]: ev.target.value} });
};
// ...
this.handleLatitudeChange = updateNestedFieldEvent('caveData.latitude');
this.handleLongitudeChange = updateNestedFieldEvent('caveData.longitude');
}
render () {
return (
<div>
<TextField id="latitude" label="Latitude" type="number" value={this.state.caveData.latitude} onChange={this.handleLatitudeChange} />
<TextField id="longitude" label="Longitude" type="number" value={this.state.caveData.longitude} onChange={this.handleLongitudeChange} />
<span>lat={this.state.caveData.latitude} long={this.state.caveData.longitude}</span>
</div>
);
};
}
注意,状态更新器函数updateNestedFieldEvent只适用于一层嵌套对象,比如a.b,而不是a.b.c。