我试图通过使用这样的嵌套属性来组织我的状态:
this.state = {
someProperty: {
flag:true
}
}
但是像这样更新状态,
this.setState({ someProperty.flag: false });
是行不通的。怎样才能正确地做到这一点呢?
我试图通过使用这样的嵌套属性来组织我的状态:
this.state = {
someProperty: {
flag:true
}
}
但是像这样更新状态,
this.setState({ someProperty.flag: false });
是行不通的。怎样才能正确地做到这一点呢?
当前回答
我用了这个方法。
如果你有一个这样的嵌套状态:
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" />
其他回答
我们使用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>
)
让我知道!
我知道这是一个老问题,但仍然想分享我是如何做到这一点的。假设构造函数中的状态是这样的:
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"
/>
我看到每个人都给出了基于类的组件状态更新解决方案,这是预期的,因为他要求,但我试图给钩子相同的解决方案。
const [state, setState] = useState({
state1: false,
state2: 'lorem ipsum'
})
现在,如果你想改变嵌套对象键state1,那么你可以做以下任何一项:
过程1
let oldState = state;
oldState.state1 = true
setState({...oldState);
流程2
setState(prevState => ({
...prevState,
state1: true
}))
我最喜欢过程。
这样就足够了,
const isObject = (thing) => {
if(thing &&
typeof thing === 'object' &&
typeof thing !== null
&& !(Array.isArray(thing))
){
return true;
}
return false;
}
/*
Call with an array containing the path to the property you want to access
And the current component/redux state.
For example if we want to update `hello` within the following obj
const obj = {
somePrimitive:false,
someNestedObj:{
hello:1
}
}
we would do :
//clone the object
const cloned = clone(['someNestedObj','hello'],obj)
//Set the new value
cloned.someNestedObj.hello = 5;
*/
const clone = (arr, state) => {
let clonedObj = {...state}
const originalObj = clonedObj;
arr.forEach(property => {
if(!(property in clonedObj)){
throw new Error('State missing property')
}
if(isObject(clonedObj[property])){
clonedObj[property] = {...originalObj[property]};
clonedObj = clonedObj[property];
}
})
return originalObj;
}
const nestedObj = {
someProperty:true,
someNestedObj:{
someOtherProperty:true
}
}
const clonedObj = clone(['someProperty'], nestedObj);
console.log(clonedObj === nestedObj) //returns false
console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true
console.log()
const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
console.log(clonedObj2 === nestedObj) // returns false
console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
//returns true (doesn't attempt to clone because its primitive type)
console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty)