何时使用功能setState

phy*_*boy 23 html javascript reactjs

在过去的几天里,我一直在学习React,看一些关于你可以编写不同元素的不同方法的教程和解释.然而,有一个我最好奇的 - setState更新/覆盖state组件属性的功能.

例如,假设我有一个具有以下内容的类:

class Photos extends React.Component {
    constructor() {
        super()
        state = {
            pictures: []
        }
    }

   componentDidMount() {
      // This is where the fetch and setState will occur (see below)
   }

    render() {
       return {
          <div className="container">
             {this.state.pictures}
          </div>
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个例子看到我从API获取图像.

鉴于我已经为此函数执行了我的获取,映射和返回 - 然后我将pictures: []使用API​​调用中获得的结果更新状态数组.

我的问题源于我见过的关于如何更新/覆盖图片状态属性的不同方法.

我看过它有两种不同的方式:

1) 这似乎是一种非常简单易读的方法

this.setState({pictures: pics})

2) 这更复杂,但我认为它被描述为更安全的方法

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))
Run Code Online (Sandbox Code Playgroud)

有人可以解释使用其中任何一个的优点吗?我想在未来与代码保持一致,处理道具和状态等,所以最通用的方法当然是首选.

Shu*_*tri 25

首先,在您的情况下,两种语法完全不同,您可能正在寻找的是两者之间的区别

this.setState({pictures: this.state.picture.concat(pics)})
Run Code Online (Sandbox Code Playgroud)

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))
Run Code Online (Sandbox Code Playgroud)

要理解为什么第二种方法是首选方法,您需要了解React在内部对setState的作用.

React将首先将您传递的对象合并setState()到当前状态.然后它将开始那个和解的事情.因为呼叫setState()可能不会立即更新您的状态.

React可以将多个setState()调用批处理为单个更新,以获得更好的性能.

考虑一下这个简单的例子,要理解这一点,在你的函数中你可以多次调用setState

myFunction = () => {

   ...
   this.setState({pictures: this.state.picture.concat(pics1)})
   this.setState({pictures: this.state.picture.concat(pics1)})
   this.setState({pictures: this.state.picture.concat(pics1)})

   ...
}
Run Code Online (Sandbox Code Playgroud)

这不是一个简单的应用程序中的有效用例,但随着应用程序变得复杂,多个setState调用可能发生在多个地方,做同样的事情.

所以现在为了执行有效的更新,React通过提取传递给每个setState()调用的所有对象来完成批处理,将它们合并在一起形成一个对象,然后使用该单个对象来执行setState().根据setState文档

如果您尝试在同一周期中多次增加项目数量,则会产生相当于:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)
Run Code Online (Sandbox Code Playgroud)

后续调用将覆盖同一周期中先前调用的值,因此数量将仅增加一次.如果下一个状态取决于先前的状态,我们建议使用更新程序功能表单

因此,如果任何对象包含相同的键,则存储具有相同键的最后一个对象的键的值.因此更新只发生一次最后一个值

演示代码盒

  • 用于演示。一个价值一千字的演示。 (3认同)

Nan*_*ndi 8

TL; DR:setStatesetState在很短的时间间隔内触发多个s 时,功能性功能主要有助于期望正确的状态更新,这与常规方式setState一样,对帐会导致意外状态。

请查看有关Function setState的精彩文章以清楚了解

这是工作演示

首先,您尝试在每种情况下做不同的事情,您在一个中分配图片,而在另一个中并置图片。

可以说this.state.pictures包含[1, 2, 3]和pics包含[4, 5, 6]

this.setState({pictures: pics})

在上述情况下,this.state.pictures将包含图片,即 this.state.pictures = [4, 5, 6]

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))
Run Code Online (Sandbox Code Playgroud)

而在以上代码段中,this.state.pictures将包含先前的图片+ pics,即 this.state.pictures = [1, 2, 3, 4, 5, 6]

无论哪种方式,您都可以对其进行调整以满足API的需求,如果它像分页的响应,那么最好将每个请求的结果串联起来,否则,如果每次都获得整个数组,则只需分配整个数组即可。

常规setState VS Functional setState

现在,您的问题可能主要是使用setState对象还是功能。

人们出于不同的原因使用这两种方法,现在setState据说该功能是安全的,因为React执行了一种称为协调过程,该过程在setState频繁或同时触发时将内部的多个对象合并在一起,并一次更改地应用更改,类似于批处理。在以下情况下,这可能会导致某些意外结果。

例:

increaseScoreBy3 () {
 this.setState({score : this.state.score + 1});
 this.setState({score : this.state.score + 1});
 this.setState({score : this.state.score + 1});
}
Run Code Online (Sandbox Code Playgroud)

如您所愿,分数将增加3,但是React所做的是合并所有对象并仅将分数更新一次,即将其增加1

这是功能回调大放异彩的情况之一,因为在函数上不进行协调,执行下面的代码将按预期完成操作,即将分数更新3

increaseScoreBy3 () {
 this.setState(prevState => ({ score: prevState.score + 1 }));
 this.setState(prevState => ({ score: prevState.score + 1 }));
 this.setState(prevState => ({ score: prevState.score + 1 }));
}
Run Code Online (Sandbox Code Playgroud)