javascript 何时使用函数式 setState

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48209452/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:52:48  来源:igfitidea点击:

When to use functional setState

javascripthtmlreactjs

提问by physicsboy

I have been learning React over the past few days, looking at a few tutorials and explanations regarding the different ways in which you can write different elements. However there is one I have been most curious about - the setStatefunction to update/override the stateproperties of a component.

过去几天我一直在学习 React,查看了一些关于编写不同元素的不同方式的教程和解释。然而,有一个我最好奇的 -setState更新/覆盖state组件属性的函数。

For example, imagine I have a class with the following:

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

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

This example sees me fetch images from an API.

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

Given that I have performed my fetch, map and return for this function - I will then update the pictures: []state array with the results gained in the API call.

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

My question stems from the differing methods I have seen regarding how to update/override the pictures state property.

我的问题源于我所看到的关于如何更新/覆盖图片状态属性的不同方法。

I have seen it written in 2 varying ways:

我已经看到它以两种不同的方式编写:

1)This seems to be a very simple and easy to read method

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

this.setState({pictures: pics})

this.setState({pictures: pics})

2)This is more complex but I have see it described as a more safe method

2)这更复杂,但我认为它是一种更安全的方法

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))

Could somebody please explain the merits of using either? I want to be consistent with code in the future, dealing with props and states etc, so the most versatile method would of course be preferred.

有人可以解释一下使用两者的优点吗?我希望将来与代码保持一致,处理道具和状态等,因此当然首选最通用的方法。

回答by Shubham Khatri

First things first, in your case the two syntaxes are entirely different, what you might be looking for is the difference between

首先,在您的情况下,这两种语法完全不同,您可能正在寻找的是

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

and

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))

To understand why the second method is a preferred one,you need to understand what React does with setState internally.

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

React will first merge the object you passed to setState()into the current state. Then it will start that reconciliation thing. Because of the calling setState()might not immediately update your state.

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

React may batch multiple setState()calls into a single update for better performance.

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

Consider the simple case, to understand this, in your function you might call setState more than once like

考虑一个简单的情况,要理解这一点,在您的函数中,您可能会多次调用 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)})

   ...
}

which isn't a valid use case in a simple app but as the app gets complex, multiple setState calls may be happening from multiple places, doing the same thing.

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

So now to perform an efficient update, React does the batching thing by extracting all the objects passed to each setState()call, merges them together to form a single object, then uses that single object to do setState(). According to setState documentation

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

If you attempt to increment an item quantity more than once in the same cycle, that will result in the equivalent of:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

Subsequent calls will override values from previous calls in the same cycle, so the quantity will only be incremented once. If the next state depends on the previous state, we recommend using the updater function form, instead

如果您尝试在同一周期内多次增加项目数量,将导致相当于:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

后续调用将覆盖同一周期中先前调用的值,因此数量只会增加一次。如果下一个状态依赖于前一个状态,我们建议使用 updater 函数形式,而不是

So if any of the objects contains the same key, the value of the key of the last object with same key is stored. And hence the update only happens once with the last value

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

Demo Codesandbox

演示代码沙盒

回答by Nandu Kalidindi

TL;DR:Functional setStateis mainly helpful to expect correct state update when multiple setStates are triggered in a short interval of time where as conventional setStatedoes reconciliation and could lead to unexpected state.

TL;DR:FunctionalsetState主要有助于setState在短时间内触发多个s时期望正确的状态更新,而传统方法setState会进行协调并可能导致意外状态。

Please check this wonderful article on Functional setStateto get a clear understanding

请查看这篇关于Functional setState 的精彩文章以获得清晰的理解

And here is the WORKING DEMO

这是工作演示

Firstly, you are trying to do different things in each of your cases, you are assigning pics in one and concatenating pics in another.

首先,您正在尝试在每个案例中做不同的事情,您在一个中分配图片并在另一个中连接图片。

Lets say this.state.pictures contain [1, 2, 3]and pics contain [4, 5, 6]

假设 this.state.pictures 包含[1, 2, 3]和 pics 包含[4, 5, 6]

this.setState({pictures: pics})

this.setState({pictures: pics})

In the above case this.state.pictures will contain the pics i.e this.state.pictures = [4, 5, 6]

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

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))

Whereas in the above snippet, this.state.pictures will contain the previous pictures + pics i.e this.state.pictures = [1, 2, 3, 4, 5, 6]

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

Either way you can tweak it to meet your API needs, if it's like a paginated response the you are better off concatenating the results on each request, else if you get the whole array each time just assign the whole array.

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

Conventional setState VS Functional setState

常规 setState VS 函数式 setState

Now, your question mainly is probably whether to use setStatewith an object or with a function.

现在,您的问题主要可能是setState与对象一起使用还是与函数一起使用。

People use both of them for different reasons, now the functional setStateis said to be safe because Reactdoes something called a reconciliation process where in it merges multiple objects inside setStatewhen triggered frequently or concurrently and applies the changes in one shot, kind of like a batch process. This could potentially lead to some unexpected results in scenarios like below.

人们出于不同的原因同时使用它们,现在setState据说该功能是安全的,因为React有一种称为协调过程的东西,其中在setState频繁或并发触发时合并内部的多个对象,并一次性应用更改,有点像批处理过程. 这可能会导致在如下场景中出现一些意想不到的结果。

EXAMPLE:

例子:

increaseScoreBy3 () {
 this.setState({score : this.state.score + 1});
 this.setState({score : this.state.score + 1});
 this.setState({score : this.state.score + 1});
}

As you would expect the score to be incremented by 3 but what React does is merge all the objects and update the score only once i.e incrementing it by 1

正如你所期望的那样,分数会增加 3,但 React 所做的是合并所有对象并只更新一次分数,即增加 1

This is one of the cases where functional callback shines because reconciliation does not happen on functions and executing the below code will do things as expected i.e update score by 3

这是函数回调发光的情况之一,因为协调不会发生在函数上并且执行以下代码将按预期执行操作,即更新分数为 3

increaseScoreBy3 () {
 this.setState(prevState => ({ score: prevState.score + 1 }));
 this.setState(prevState => ({ score: prevState.score + 1 }));
 this.setState(prevState => ({ score: prevState.score + 1 }));
}

回答by Nitin Jadhav

A Quick answer:

快速回答:

Always use functional form of setState().

始终使用 setState() 的函数形式。

this.setState((state, props)=>({
    someValue: state.somevalue + 1
}));

This approach is less error-prone and helps to eliminate some very hard-to-find bugs. Even if react batches multiple such updates, each update is separate function call and subsequent updates will not cause some of these updates to be lost.

这种方法不易出错,有助于消除一些非常难以发现的错误。即使 react 批量处理多个这样的更新,每次更新都是单独的函数调用,后续更新不会导致其中一些更新丢失。

The other approach

另一种方法

this.setState({
someValue: state.somevalue + 1
});

If repeated frequently, might cause some of the updates to be lost, since React batches such frequent updates.

如果频繁重复,可能会导致某些更新丢失,因为 React 会批量处理如此频繁的更新。