这实际上是变异状态吗?一个不好的做法? - 反应

时间:2018-01-22 07:28:37

标签: reactjs

这是我遇到的一段代码,我不确定它到底在做什么? 我感觉它好像正在改变国家     版本1:

 this.state.items = [...this.state.initialItems];

现在,上面的代码是变异状态??

以上也可以写成第2版:

this.setState({
   items:[...this.state.initialItems];
});

问题是版本1正在运行,但版本2不是。 那么,这里有什么问题? 我错过了什么? ...this.state.initialItems做了什么?是扩散算子吗?

3 个答案:

答案 0 :(得分:2)

这段代码肯定是变异状态。不要这样做:

this.state.items = [...this.state.initialItems];

是的,...在这种情况下是一个传播运算符。

对于版本2,请确保不使用分号。 它应该只是:

this.setState({
   items:[...this.state.initialItems]
});

当然,就像下面的海报所说,它是异步的,所以你不会马上看到结果。

增强1:
如果你想在状态准备好之后做一些事情,你可以添加一个回调作为setState的第二个参数。

this.setState({
   items:[...this.state.initialItems]
  }, ()=>{
   // do stuff
  }
);

增强2:
您对setState的第一个参数也可以是一个函数,正如另一个海报所提到的那样,当您访问状态时,它将是“最新鲜”的副本,而不是您创建传递给的对象时捕获的副本。 setstate这:

this.setState((stateNOW) => {
   return {items:[...stateNOW.initialItems]};
  }, ()=>{
   // do stuff
  }
);

答案 1 :(得分:1)

版本1正在改变您的状态,这是一种不好的做法。

版本2不是,无效(实际上是)的原因是对setState的调用是asynchronous因此您将无法访问它下一行中的最新值。

如果您需要访问新的州值,可以使用:

this.setState(prevState => ({
  items: [...prevState.initialItems],
}), () => {
  console.log(this.state) // new state value
})

请参阅ReactJS文档中的this link,了解如何正确设置状态。

...确实是spread syntax

您可以使用它,例如:

将项目添加到数组

const arr = [1, 2, 3, 4]
const newArr = [...arr, 5, 6] // This will spread everything in arr and add numbers 5 and 6 to newArr

console.log('arr', arr)
console.log('newArr', newArr)

从数组中获取项目

const arr = [1,2,3,4]
const [firstItem, secondItem, ...others] = arr

console.log('firstItem:', firstItem)
console.log('secondItem:', secondItem)
console.log('others:', others)

创建新对象

const obj = {
  name: 'Stack Overflow',
  age: 10,
}

const newObj = {
  ...obj, // gets all properties from obj
  age: 12, // but only change age
}

console.log('obj', obj)
console.log('newObj', newObj)

答案 2 :(得分:1)

版本1错了。但真正的问题是为什么? state是React中的一个特殊对象,它不会被变异。

假设您声明了一个对象:

const obj = {
  label: 'doe'
  value: 'foo'
}

然后,您使用

更新obj

obj.value = 'bar'

这是突变的过程,不应该使用状态变量执行它。相反,我们使用setState作为更改状态的请求。

...spread syntax

正如其他答案所提到的,您认为它不起作用的原因可能是因为状态更新是异步的。 您必须使用setState回调或componentDidUpdate生命周期挂钩来记录状态值。

setState(stateChange[, callback])

代码中的另一个问题是在setState中使用this.state.something。就像我们之前提到的那样setState是异步的,并且可以合并许多状态更新。因此,如果您错过了更新,那么使用this.state.initialItems可能并不总能为您服务。

this.setState((prevState) => {
  return {items: [...prevState.initialItems]};
}); 

这是使用先前状态值的正确方法。