在 React 中使用 setState 更新对象

IT技术 reactjs state
2021-04-03 23:37:02

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

就像是:

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

我努力了:

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

还有这个:

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

第一个导致语法错误,第二个什么也不做。有任何想法吗?

6个回答

有多种方法可以做到这一点,因为状态更新是一个异步操作,所以要更新状态对象,我们需要使用updater 函数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.assign andSpread Operator只创建浅拷贝,因此如果您定义了嵌套对象或对象数组,则需要不同的方法。


更新嵌套状态对象:

假设您已将状态定义为:

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'
    }
  ]
}

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

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

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

}))

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

@JohnSnow 在你第二个它会从jasper对象中删除其他属性console.log(jasper)你只会看到一个键name,年龄不会存在:)
2021-05-24 23:37:02
@JohnSnow,是jasperobject如果这样的话,这种方式是正确,不管是否最好,可能还有其他更好的解决方案:)
2021-05-25 23:37:02
@ankur_rajput 我们使用扩展运算符来创建浅拷贝,您也可以使用 Object.assign。避免状态对象的直接突变。
2021-05-31 23:37:02
怎么样let { jasper } = this.state
2021-06-01 23:37:02
很高兴在这里提一下,既不Object.assign传播也不传播运算符的深度复制属性。通过这种方式,您应该使用 lodashdeepCopy解决方法
2021-06-10 23:37:02

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

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

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

这种解决方案有一个很大的缺点:为了优化状态更新,React 可能会将多个更新分组。因此this.state.jasper不一定包含最新状态。更好地使用带有prevState.
2021-06-11 23:37:02

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

this.setState({
    jasper: {
          ...this.state.jasper,
          name: 'something'
    }
})
这会更新 jasper,但其他属性将从状态中删除。
2021-06-17 23:37:02

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

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

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

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

因为您使用了两个只需要一个的语句。
2021-05-21 23:37:02

我使用了这个解决方案。

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

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" />
这对我有用,但我不得不改用它: statusCopy.formInputs[inputName] = inputValue;
2021-05-28 23:37:02