在React中使用setState更新对象

Joh*_*now 211 state reactjs

是否可以使用setState更新对象的属性?

就像是:

this.state = {
   jasper: { name: 'jasper', age: 28 },
}
Run Code Online (Sandbox Code Playgroud)

我试过了:

this.setState({jasper.name: 'someOtherName'});
Run Code Online (Sandbox Code Playgroud)

还有这个:

this.setState({jasper: {name: 'someothername'}})
Run Code Online (Sandbox Code Playgroud)

第一个是语法错误,第二个什么都不做.有任何想法吗?

May*_*kla 440

有多种方法可以做到这一点.

1-最简单的一个:

首先创建一个副本,setState然后执行以下更改:

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
})
Run Code Online (Sandbox Code Playgroud)

而不是使用jasper我们也可以像这样写:

let jasper = { ...prevState.jasper };
Run Code Online (Sandbox Code Playgroud)

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
    }
}))
Run Code Online (Sandbox Code Playgroud)

  • @JohnSnow在你的第二个它将从`jasper`对象中删除其他属性,执行`console.log(jasper)`你只会看到一个键`name`,年龄不会在那里:) (6认同)
  • 这里要提的是既没有'Object.assign`也没有传播运算符深度复制属性.这样你就应该使用像lodash`sharpCopy`这样的解决方法. (5认同)

Raj*_*sit 29

使用钩子我们可以这样做

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


man*_*nok 27

最快,最易读的方式:

this.setState({...this.state.jasper, name: 'someothername'});
Run Code Online (Sandbox Code Playgroud)

虽然this.state.jasper已经包含一个名称属性,后者name: 'someothername'可以使用.

  • 此解决方案有一个很大的缺点:为了优化状态更新,React可能会对多个更新进行分组.因此,`this.state.jasper`不一定包含最新的状态.更好地使用`prevState`的表示法. (29认同)

小智 26

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

this.setState({
    jasper: {
          ...this.state.jasper,
          name: 'something'
    }
})
Run Code Online (Sandbox Code Playgroud)

  • 这会更新 jasper,但其他属性将从状态中删除。 (3认同)

col*_*ick 23

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

const jasper = { ...this.state.jasper, name: 'someothername' }
this.setState(() => ({ jasper }))
Run Code Online (Sandbox Code Playgroud)

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

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

  • 因为您使用了两条语句,而只需要一条语句。 (5认同)

Alb*_*ras 8

我用过这个解决方案.

如果您有这样的嵌套状态:

this.state = {
  formInputs:{
    friendName:{
      value:'',
      isValid:false,
      errorMsg:''
    },
    friendEmail:{
      value:'',
      isValid:false,
      errorMsg:''
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以声明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);
  }
Run Code Online (Sandbox Code Playgroud)

这里是带有事件监听器的html.确保使用与状态对象相同的名称(在本例中为'friendName')

<input type="text" onChange={this.handleChange} " name="friendName" />
Run Code Online (Sandbox Code Playgroud)


Vin*_*mar 7

创建状态对象

this.state = {
  objName: {
    propertyOne: "",
    propertyTwo: ""
  }
};
Run Code Online (Sandbox Code Playgroud)

使用更新状态setState

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


Anu*_*thi 7

在功能组件中使用钩子:

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

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


小智 6

试试这个,它应该工作正常

this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));
Run Code Online (Sandbox Code Playgroud)

  • 您正在直接改变状态对象。要使用此方法,请添加一个新对象作为源:``Object.assign({}, this.state.jasper, {name:'someOtherName'})``` (7认同)

sam*_*war 5

这是使用immer immutabe 实用程序的另一种解决方案,非常适合轻松深度嵌套的对象,并且您不应该关心突变

this.setState(
    produce(draft => {
       draft.jasper.name = 'someothername'
    })
)
Run Code Online (Sandbox Code Playgroud)