在React中使用setState更新对象

是否有可能用setState更新对象的属性?

喜欢的东西:

this.state = {
jasper: { name: 'jasper', age: 28 },
}

我试过:

this.setState({jasper.name: 'someOtherName'});

这:

this.setState({jasper: {name: 'someothername'}})

第一个会导致语法错误,第二个则什么都不做。什么好主意吗?

642516 次浏览

有多种方法可以做到这一点,因为状态更新是一个异步操作,所以要更新状态对象,我们需要使用更新功能setState

1-最简单的一个:

首先创建jasper的副本,然后对其进行更改:

this.setState(prevState => {
let jasper = Object.assign({}, prevState.jasper);  // creating copy of state variable jasper
jasper.name = 'someothername';                     // update the name property, assign a new value
return { jasper };                                 // return new object jasper object
})

我们可以不使用Object.assign,而是这样写:

let jasper = { ...prevState.jasper };

2-使用扩展语法:

this.setState(prevState => ({
jasper: {                   // object that we want to update
...prevState.jasper,    // keep all other key-value pairs
name: 'something'       // update the value of specific key
}
}))

注意: Object.assignSpread Operator只创建浅拷贝,所以如果你定义了嵌套对象或对象数组,你需要不同的方法。


更新嵌套状态对象:

假设你已经将state定义为:

this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}

更新比萨饼对象的extraCheese:

this.setState(prevState => ({
food: {
...prevState.food,           // copy all other key-value pairs of food object
pizza: {                     // specific object of food object
...prevState.food.pizza,   // copy all pizza key-value pairs
extraCheese: true          // update value of specific key
}
}
}))

更新对象数组:

让我们假设你有一个todo应用程序,你正在以这样的形式管理数据:

this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}

要更新任何todo对象的状态,在数组上运行一个map并检查每个对象的某个唯一值,如果是condition=true,则返回具有更新值的新对象,否则是相同的对象。

let key = 2;
this.setState(prevState => ({


todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)


}))

建议:如果object没有唯一值,则使用数组索引。

第一种情况确实是语法错误。

因为我看不到组件的其余部分,所以很难理解为什么要在这里的状态中嵌套对象。在组件状态下嵌套对象不是一个好主意。尝试将初始状态设置为:

this.state = {
name: 'jasper',
age: 28
}

这样,如果你想要更新名称,你可以调用:

this.setState({
name: 'Sean'
});

这能达到你的目标吗?

对于更大、更复杂的数据存储,我会使用Redux之类的东西。但这要高级得多。

关于组件状态的一般规则是只使用它来管理组件的UI状态(例如,活动,计时器等)。

看看这些参考资料:

另一种选择:用碧玉对象定义变量,然后直接调用一个变量。

扩展操作符:ES6

this.state = {  jasper: { name: 'jasper', age: 28 } }


let foo = "something that needs to be saved into state"


this.setState(prevState => ({
jasper: {
...jasper.entity,
foo
}
})

我用了这个方法。

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

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。确保使用与状态对象相同的名称(在本例中为'friendName')

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

这是最快和最易读的方式:

this.setState({...this.state.jasper, name: 'someothername'});

即使this.state.jasper已经包含name属性,也会使用新名称name: 'someothername'

这里使用展开运算符和一些ES6

this.setState({
jasper: {
...this.state.jasper,
name: 'something'
}
})

同样,按照Alberto Piras解决方案,如果你不想复制所有的“state”对象:

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


let jasperCopy = Object.assign({}, this.state.jasper);
jasperCopy[inputName].name = inputValue;


this.setState({jasper: jasperCopy});
}

试试这个,应该没问题

this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));

你可以试试这个:

this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.name = 'someOtherName';
return {jasper: prevState}
})

或其他财产:

this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.age = 'someOtherAge';
return {jasper: prevState}
})

或者你可以使用handleChage函数:

handleChage(event) {
const {name, value} = event.target;
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState[name] = value;
return {jasper: prevState}
})
}

和HTML代码:

<input
type={"text"}
name={"name"}
value={this.state.jasper.name}
onChange={this.handleChange}
/>
<br/>
<input
type={"text"}
name={"age"}
value={this.state.jasper.age}
onChange={this.handleChange}
/>
< p > 你可以试试这个: (请注意: name of input tag === field of object)

<input name="myField" type="text"
value={this.state.myObject.myField}
onChange={this.handleChangeInpForm}>
</input>


-----------------------------------------------------------
handleChangeInpForm = (e) => {
let newObject = this.state.myObject;
newObject[e.target.name] = e.target.value;
this.setState({
myObject: newObject
})
}

简单而动态的方式。

这将完成工作,但你需要设置所有的id为父,所以父将指向对象的名称,id = "jasper",并命名输入元素的名称=属性在对象jasper。

handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });

不使用异步和等待使用此…

funCall(){
this.setState({...this.state.jasper, name: 'someothername'});
}

如果你使用异步和等待使用这个…

async funCall(){
await this.setState({...this.state.jasper, name: 'someothername'});
}

这是另一个使用其次是音麦 immutabe实用程序的解决方案,非常适合于深度嵌套的对象,并且您不应该关心突变

this.setState(
produce(draft => {
draft.jasper.name = 'someothername'
})
)

我知道这里有很多答案,但我很惊讶他们没有一个在setState之外创建一个新对象的副本,然后简单地setState({newObject})。干净、简洁、可靠。在这种情况下:

const jasper = { ...this.state.jasper, name: 'someothername' }
this.setState(() => ({ jasper }))

或者动态属性(对表单非常有用)

const jasper = { ...this.state.jasper, [VarRepresentingPropertyName]: 'new value' }
this.setState(() => ({ jasper }))

这个设置对我来说很管用:

let newState = this.state.jasper;
newState.name = 'someOtherName';


this.setState({newState: newState});


console.log(this.state.jasper.name); //someOtherName

第二种方法不起作用,因为{name: 'someothername'}等于{name: 'someothername', age: undefined},所以__abc2会覆盖原始的年龄值。

当涉及到改变嵌套对象的状态时,一个很好的方法是Immutable.js

this.state = {
jasper: Record({name: 'jasper', age: 28})
}


const {jasper} = this.state
this.setState({jasper: jasper.set(name, 'someothername')})

试试这个:

const { jasper } = this.state; //Gets the object from state
jasper.name = 'A new name'; //do whatever you want with the object
this.setState({jasper}); //Replace the object in state

创建一个状态对象

this.state = {
objName: {
propertyOne: "",
propertyTwo: ""
}
};

使用setState更新状态

this.setState(prevState => ({
objName: {
...prevState.objName,
propertyOne: "Updated Value",
propertyTwo: "Updated value"
}
}));

在更新对象的情况下,键是字符串

例如,你的状态对象是

serviceDays: {
Sunday: true,
Monday: true,
Tuesday: false,
Wednesday: true,
Thurday: false,
Friday: true,
Saturday: true
}

所以你可以通过以下方式更新

const onDayClick = day => {
const { serviceDays } = this.state
this.setState(prevState => ({
serviceDays: {
...prevState.serviceDays,
[day]: serviceDays[day] ? false : true
}
}))
}

通过使用input html的input name属性,我们可以有一个更动态的方法来更新对象属性。

< >强DOM HTML输入名称属性 < / p >

<input type="text" name="fname" handleChange={(e: any) => { updatePerson(e) }}/>
<input type="text" name="lname" handleChange={(e: any) => { updatePerson(e) }}/>

React / TSX object.assign < / p >

const [person, setPerson] = useState<IPerson>({});


function updatePerson(e: React.ChangeEvent<HTMLInputElement>): void {
const { name, value } = e.currentTarget;


setPerson(prevState => {
const newState = Object.assign(person, { [name]: value })
return { ...prevState, ...newState };
});
}

舰队指挥官:样品

   const [formData, setformData] = useState({
project_admin_permissions: {
task_forms: false,
auto_assign_rules: false,
project_notes: true,
alerts: false,
update_criteria: true,
project_flow: false,
reports: false,
}
        

})
    

const handleChangeCheckBox = (e) => {
setformData({
...formData, project_admin_permissions: { ...formData.project_admin_permissions, [e.target.name]: e.target.checked }
    

})
}

使用钩子,我们可以做到以下方式

const [student, setStudent] = React.useState({name: 'jasper', age: 28});
setStudent((prevState) => ({
...prevState,
name: 'newName',
}));

在功能组件中使用钩子:

const [state, setState] = useState({jasper: { name: 'jasper', age: 28 }})
const nameChangeHandler = () => {
setState(prevState => ({
...prevState,
prevState.jasper.name = "Anurag",
prevState.jasper.age = 28
})
)
}

在这些情况下,建议使用基于回调的方法来更新状态,因为使用这种方法可以确保之前的状态被完全更新,并且我们正在基于之前更新的状态进行更新。