在 React 中使用 setState 更新对象
Updating an object with setState in React
是否可以使用 setState
更新对象的属性?
类似于:
this.state = {
jasper: { name: 'jasper', age: 28 },
}
我试过:
this.setState({jasper.name: 'someOtherName'});
还有这个:
this.setState({jasper: {name: 'someothername'}})
第一个导致语法错误,第二个什么都不做。有什么想法吗?
有多种方法可以做到这一点,因为状态更新是 , so to update the state object, we need to use updater function 和 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- 使用 spread syntax:
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.assign
和Spread Operator
只创建shallow copy,所以如果你定义了嵌套对象或对象数组,你需要一种不同的方法。
正在更新嵌套状态对象:
假设您将状态定义为:
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
}
}
}))
正在更新对象数组:
假设您有一个待办事项应用程序,并且您正在以这种形式管理数据:
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
要更新任何待办事项对象的状态,运行 数组上的映射并检查每个对象的某些唯一值,以防 condition=true
、return 新具有更新值的对象,否则为同一对象。
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
建议:如果对象没有唯一值,则使用数组索引。
第一种情况确实是语法错误
由于我看不到您组件的其余部分,所以很难看出您为什么要在此处嵌套状态中的对象。在组件状态中嵌套对象不是一个好主意。尝试将初始状态设置为:
this.state = {
name: 'jasper',
age: 28
}
这样,如果你想更新名字,你可以调用:
this.setState({
name: 'Sean'
});
这会实现您的目标吗?
对于更大、更复杂的数据存储,我会使用 Redux 之类的东西。但这要高级得多。
组件状态的一般规则是仅使用它来管理组件的UI状态(例如活动、计时器等)
查看这些参考资料:
另一种选择:从 Jasper 对象中定义变量,然后调用一个变量。
展开运算符: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 函数并re-assigns它具有更改后的值
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: '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}
/>
你可以试试这个:
(注意:输入标签的名称==对象的字段)
<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 } });
不使用 Async 和 Await 使用这个...
funCall(){
this.setState({...this.state.jasper, name: 'someothername'});
}
如果你使用 Async And Await 使用这个...
async funCall(){
await this.setState({...this.state.jasper, name: 'someothername'});
}
这是另一个使用 immer immutabe 实用程序的解决方案,非常适合轻松地深层嵌套对象,您不应该关心突变
this.setState(
produce(draft => {
draft.jasper.name = 'someothername'
})
)
我知道这里有很多答案,但令我惊讶的是 none 他们在 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}
,因此 undefined
会覆盖原始年龄值。
当谈到改变嵌套对象的状态时,一个好的方法是 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
}
}))
}
通过使用输入 html 输入名称属性,我们可以采用更动态的方法来更新对象属性。
<input type="text" name="fname" handleChange={(e: any) => { updatePerson(e) }}/>
<input type="text" name="lname" handleChange={(e: any) => { updatePerson(e) }}/>
反应/TSX
object.assign
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 };
});
}
FC 示例:
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 }
})
}
使用hook我们可以做如下的事情
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
})
)
}
在这些情况下,建议使用 callback-based 方法来更新状态,因为使用这种方法可以确保之前的状态得到完全更新,并且我们正在根据之前更新的状态进行更新。
是否可以使用 setState
更新对象的属性?
类似于:
this.state = {
jasper: { name: 'jasper', age: 28 },
}
我试过:
this.setState({jasper.name: 'someOtherName'});
还有这个:
this.setState({jasper: {name: 'someothername'}})
第一个导致语法错误,第二个什么都不做。有什么想法吗?
有多种方法可以做到这一点,因为状态更新是 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- 使用 spread syntax:
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.assign
和Spread Operator
只创建shallow copy,所以如果你定义了嵌套对象或对象数组,你需要一种不同的方法。
正在更新嵌套状态对象:
假设您将状态定义为:
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
}
}
}))
正在更新对象数组:
假设您有一个待办事项应用程序,并且您正在以这种形式管理数据:
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
要更新任何待办事项对象的状态,运行 数组上的映射并检查每个对象的某些唯一值,以防 condition=true
、return 新具有更新值的对象,否则为同一对象。
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
建议:如果对象没有唯一值,则使用数组索引。
第一种情况确实是语法错误
由于我看不到您组件的其余部分,所以很难看出您为什么要在此处嵌套状态中的对象。在组件状态中嵌套对象不是一个好主意。尝试将初始状态设置为:
this.state = {
name: 'jasper',
age: 28
}
这样,如果你想更新名字,你可以调用:
this.setState({
name: 'Sean'
});
这会实现您的目标吗?
对于更大、更复杂的数据存储,我会使用 Redux 之类的东西。但这要高级得多。
组件状态的一般规则是仅使用它来管理组件的UI状态(例如活动、计时器等)
查看这些参考资料:
另一种选择:从 Jasper 对象中定义变量,然后调用一个变量。
展开运算符: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 函数并re-assigns它具有更改后的值
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: '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}
/>
你可以试试这个: (注意:输入标签的名称==对象的字段)
<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 } });
不使用 Async 和 Await 使用这个...
funCall(){
this.setState({...this.state.jasper, name: 'someothername'});
}
如果你使用 Async And Await 使用这个...
async funCall(){
await this.setState({...this.state.jasper, name: 'someothername'});
}
这是另一个使用 immer immutabe 实用程序的解决方案,非常适合轻松地深层嵌套对象,您不应该关心突变
this.setState(
produce(draft => {
draft.jasper.name = 'someothername'
})
)
我知道这里有很多答案,但令我惊讶的是 none 他们在 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}
,因此 undefined
会覆盖原始年龄值。
当谈到改变嵌套对象的状态时,一个好的方法是 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
}
}))
}
通过使用输入 html 输入名称属性,我们可以采用更动态的方法来更新对象属性。
<input type="text" name="fname" handleChange={(e: any) => { updatePerson(e) }}/>
<input type="text" name="lname" handleChange={(e: any) => { updatePerson(e) }}/>
反应/TSX object.assign
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 };
});
}
FC 示例:
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 }
})
}
使用hook我们可以做如下的事情
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
})
)
}
在这些情况下,建议使用 callback-based 方法来更新状态,因为使用这种方法可以确保之前的状态得到完全更新,并且我们正在根据之前更新的状态进行更新。