函数setState是React的未来

by Justice Mba

由Mba法官

函数setState是React的未来 (Functional setState is the future of React)

Update: I gave a follow up talk on this topic at React Rally. While this post is more about the “functional setState” pattern, the talk is more about understanding setState deeply

更新:我在React Rally上进行了关于该主题的后续讨论。 尽管这篇文章更多地是关于“功能性setState”模式的,但该演讲更多是关于深刻理解setState的。

React has popularized functional programming in JavaScript. This has led to giant frameworks adopting the Component-based UI pattern that React uses. And now functional fever is spilling over into the web development ecosystem at large.

React已经在JavaScript中普及了函数式编程。 这导致巨型框架采用了React使用的基于组件的UI模式。 现在,功能热已经泛滥到整个Web开发生态系统中。

But the React team is far from relenting. They continue to dig deeper, discovering even more functional gems hidden in the legendary library.

但是,React团队还远远没有屈服。 他们继续进行更深入的挖掘,发现隐藏在传奇库中的更多实用宝石。

So today I reveal to you a new functional gold buried in React, best kept React secret — Functional setState!

因此,今天我向您揭示一个埋在React中的新功能金,最好保留React的秘密-Functional setState!

Okay, I just made up that name… and it’s not entirely new or a secret. No, not exactly. See, it’s a pattern built into React, that’s only known by few developers who’ve really dug in deep. And it never had a name. But now it does — Functional setState!

好吧,我只是做了这个名字......,它不是全新的或秘密。 不,不完全是。 瞧,这是React内置的一种模式,只有真正深入研究的开发人员才知道。 它从来没有一个名字。 但现在可以了- 功能性setState!

Going by Dan Abramov’s words in describing this pattern, Functional setState is a pattern where you

Dan Abramov的话描述这种模式, Functional setState是一种模式,您可以在其中

“Declare state changes separately from the component classes.”
“声明状态更改与组件类分开。”

Huh?

??

好吧...你已经知道了 (Okay… what you already know)

React is a component based UI library. A component is basically a function that accept some properties and return a UI element.

React是一个基于组件的UI库。 组件基本上是一个接受某些属性并返回UI元素的函数。

function User(props) {  return (    <div>A pretty user</div>  );}

A component might need to have and manage its state. In that case, you usually write the component as a class. Then you have its state live in the class constructor function:

组件可能需要具有并管理其状态。 在这种情况下,通常将组件编写为类。 然后,将其状态保存在类constructor函数中:

class User {  constructor () {    this.state = {      score : 0    };  }
render () {    return (      <div>This user scored {this.state.score}</div>    );  }}

To manage the state, React provides a special method called setState(). You use it like this:

为了管理状态,React提供了一个名为setState()的特殊方法。 您可以这样使用它:

class User {  ...
increaseScore () {    this.setState({score : this.state.score + 1});  }
...}

Note how setState() works. You pass it an object containing part(s) of the state you want to update. In other words, the object you pass would have keys corresponding to the keys in the component state, then setState() updates or sets the state by merging the object to the state. Thus, “set-State”.

注意setState()工作方式。 您向它传递了一个对象,其中包含要更新的状态的一部分。 换句话说,您传递的对象将具有与组件状态下的键相对应的键,然后setState()通过将对象合并为状态来更新或设置状态。 因此,“设置状态”。

你可能不知道的 (What you probably didn’t know)

Remember how we said setState() works? Well, what if I told you that instead of passing an object, you could pass a function?

还记得我们说过setState()是如何工作的吗? 好吧,如果我告诉您可以传递函数而不是传递对象怎么办?

Yes. setState() also accepts a function. The function accepts the previous state and current props of the component which it uses to calculate and return the next state. See it below:

是。 setState()也接受一个函数。 该函数接受用于计算并返回下一个状态的组件的先前状态和当前属性。 在下面看到它:

this.setState(function (state, props) { return {  score: state.score - 1 }});

Note that setState() is a function, and we are passing another function to it(functional programming… functional setState) . At first glance, this might seem ugly, too many steps just to set-state. Why will you ever want to do this?

请注意, setState()是一个函数,我们将另一个函数传递给它(函数式编程… 函数setState )。 乍一看,这似乎很难看,只是设定状态需要太多步骤。 您为什么要这样做?

为什么将函数传递给setState? (Why pass a function to setState?)

The thing is, state updates may be asynchronous.

问题是, 状态更新可能是异步的

Think about what happens when setState() is called. React will first merge the object you passed to setState() into the current state. Then it will start that reconciliation thing. It will create a new React Element tree (an object representation of your UI), diff the new tree against the old tree, figure out what has changed based on the object you passed to setState() , then finally update the DOM.

想想调用 setState () 时会发生什么 。 React将首先将您传递给setState()的对象合并到当前状态。 然后,它将开始进行对帐 。 它将创建一个新的React Element树(UI的对象表示),将新树与旧树进行比较,根据传递给setState()的对象找出发生了什么变化,然后最终更新DOM。

Whew! So much work! In fact, this is even an overly simplified summary. But trust in React!

ew! 这么多工作! 实际上,这甚至是一个过于简化的摘要。 但是相信React!

React does not simply “set-state”.
React并非简单地“设置状态”。

Because of the amount of work involved, calling setState() might not immediately update your state.

由于涉及大量工作,因此调用setState()可能不会立即更新您的状态。

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

React可以将多个setState()调用批处理到单个更新中以提高性能。

What does React mean by this?

这是什么意思?

First, “multiple setState() calls” could mean calling setState() inside a single function more than once, like this:

首先,“ 多个setState()调用”可能意味着在单个函数内多次调用setState() ,如下所示:

...
state = {score : 0};
// multiple setState() callsincreaseScoreBy3 () { this.setState({score : this.state.score + 1}); this.setState({score : this.state.score + 1}); this.setState({score : this.state.score + 1});}
...

Now when React, encounters “multiple setState() calls”, instead of doing that “set-state” three whole times, React will avoid that huge amount of work I described above and smartly say to itself: “No! I’m not going to climb this mountain three times, carrying and updating some slice of state on every single trip. No, I’d rather get a container, pack all these slices together, and do this update just once.” And that, my friends, is batching!

现在,当React过来,遇到“ setState()而不是这样做,“设定状态” 三整倍 ,阵营会避免我上述的工作是巨大的数量和巧妙地说自己叫”,“不! 我不会三度攀登这座山,每次旅行都会携带并更新一些状态。 不,我宁愿得到一个容器,将所有这些切片打包在一起,并只进行一次此更新。” 我的朋友们就是 批处理

Remember that what you pass to setState() is a plain object. Now, assume anytime React encounters “multiple setState() calls”, it 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() .

请记住,传递给setState()是一个普通对象。 现在,假设React在任何时候遇到“ 多个setState()调用”,它将通过提取传递给每个setState()调用的所有对象来进行批处理,将它们合并在一起形成一个对象,然后使用该单个对象执行setState()

In JavaScript merging objects might look something like this:

在JavaScript中,合并对象可能看起来像这样:

const singleObject = Object.assign(  {},   objectFromSetState1,   objectFromSetState2,   objectFromSetState3);

This pattern is known as object composition.

这种模式称为对象合成。

In JavaScript, the way “merging” or composing objects works is: if the three objects have the same keys, the value of the key of the last object passed to Object.assign() wins. For example:

在JavaScript中,“合并”或组成对象的工作方式是:如果三个对象具有相同的键,则传递给Object.assign()最后一个对象的键的值将获胜。 例如:

const me  = {name : "Justice"},       you = {name : "Your name"},      we  = Object.assign({}, me, you);
we.name === "Your name"; //true
console.log(we); // {name : "Your name"}

Because you are the last object merged into we, the value of name in the you object — “Your name” — overrides the value of name in the me object. So “Your name” makes it into the we object… you win! :)

因为you是合并到we中的最后一个对象,所以you对象中name的值(“您的名字”)将覆盖me对象中name的值。 因此,“您的名字”成为we对象…… you赢了! :)

Thus, if you call setState() with an object multiple times — passing an object each time — React will merge. Or in other words, it will compose a new object out of the multiple objects we passed it. And if any of the objects contains the same key, the value of the key of the last object with same key is stored. Right?

因此,如果您多次调用一个对象的setState()每次都传递一个对象),React将合并 。 换句话说,它将在我们传递给它的多个对象中构成一个新对象。 并且,如果任何对象包含相同的键,则存储具有相同键的最后一个对象的键的值。 对?

That means that, given our increaseScoreBy3 function above, the final result of the function will just be 1 instead of 3, because React did not immediately update the state in the order we called setState() . But first, React composed all the objects together, which results to this: {score : this.state.score + 1} , then only did “set-state” once — with the newly composed object. Something like this: User.setState({score : this.state.score + 1}.

这意味着,鉴于以上我们的increaseScoreBy3函数,该函数的最终结果将是1而不是3,因为React不会立即按照我们称为setState()的顺序更新状态。 但是首先,React将所有对象组合在一起,结果是: {score : this.state.score + 1} ,然后只对新组合的对象执行一次“设置状态”。 这样的东西: User.setState({score : this.state.score + 1}

To be super clear, passing object to setState() is not the problem here. The real problem is passing object to setState() when you want to calculate the next state from the previous state. So stop doing this. It’s not safe!

要非常清楚,将对象传递给setState()并不是这里的问题。 真正的问题是,当您想从前一个状态计算下一个状态时,将对象传递给setState() 。 因此,请停止这样做。 不安全!

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

由于this.propsthis.state可以异步更新,因此您不应依赖于它们的值来计算下一个状态。

Here is a pen by Sophia Shoemaker that demos this problem. Play with it, and pay attention to both the bad and the good solutions in this pen:

这是Sophia Shoemaker的一支笔,演示了此问题。 试一试,并注意这支笔的优缺点:

抢救功能setState (Functional setState to the rescue)

If you’ve not spent time playing with the pen above, I strongly recommend that you do, as it will help you grasp the core concept of this post.

如果您还没有花时间玩上面的笔,我强烈建议您这样做,因为它可以帮助您掌握本文的核心概念。

While you were playing with the pen above, you no doubt saw that functional setState fixed our problem. But how, exactly?

当您在上面玩笔时,您无疑会看到函数setState解决了我们的问题。 但是如何呢?

Let’s consult the Oprah of React — Dan.

让我们咨询一下React的Oprah-Dan。

Note the answer he gave. When you do functional setState…

注意他给的答案。 当您执行功能setState时...

Updates will be queued and later executed in the order they were called.
更新将排队,然后按调用顺序执行。

So, when React encounters “multiple functional setState() calls” , instead of merging objects together, (of course there are no objects to merge) React queues the functions “in the order they were called.”

因此,当React遇到“ 多个functional setState()调用”时,与其将对象合并在一起(当然,没有要合并的对象),React会按“ 它们被调用的顺序对这些函数进行排队

After that, React goes on updating the state by calling each functions in the “queue”, passing them the previous state — that is, the state as it was before the first functional setState() call (if it’s the first functional setState() currently executing) or the state with the latest update from the previous functional setState() call in the queue.

之后,React通过在“队列”中调用每个函数,并向它们传递先前的状态(即,与第一个函数setState()调用之前的状态(如果是第一个函数setState()一样))来继续更新状态。当前正在执行)或队列中上一个函数setState()调用的最新更新状态。

Again, I think seeing some code would be great. This time though, we’re gonna fake everything. Know that this is not the real thing, but is instead just here to give you an idea of what React is doing.

同样,我认为看到一些代码会很棒。 但这一次,我们将假装一切。 要知道,这是不是真实的东西,但是是不是只是在这里给你的React是什么做的想法

Also, to make it less verbose, we’ll use ES6. You can always write the ES5 version later if you want.

另外,为了使它不那么冗长,我们将使用ES6。 如果需要,您以后总是可以编写ES5版本。

First, let’s create a component class. Then, inside it, we’ll create a fake setState() method. Also, our component would have a increaseScoreBy3() method, which will do a multiple functional setState. Finally, we’ll instantiate the class, just as React would do.

首先,让我们创建一个组件类。 然后,在其中创建一个伪造的 setState()方法。 另外,我们的组件将具有一个increaseScoreBy3() method 它将执行多功能setState。 最后,我们将像React一样实例化该类。

class User{  state = {score : 0};
//let's fake setState  setState(state, callback) {    this.state = Object.assign({}, this.state, state);    if (callback) callback();  }
// multiple functional setState call  increaseScoreBy3 () {    this.setState( (state) => ({score : state.score + 1}) ),    this.setState( (state) => ({score : state.score + 1}) ),    this.setState( (state) => ({score : state.score + 1}) )  }}
const Justice = new User();

Note that setState also accepts an optional second parameter — a callback function. If it’s present React calls it after updating the state.

请注意,setState还接受可选的第二个参数-回调函数。 如果存在,React在更新状态后调用它。

Now when a user triggers increaseScoreBy3(), React queues up the multiple functional setState. We won’t fake that logic here, as our focus is on what actually makes functional setState safe. But you can think of the result of that “queuing” process to be an array of functions, like this:

现在,当用户触发gainScoreBy3 increaseScoreBy3() ,React将多功能setState排队。 我们不会在这里伪造该逻辑,因为我们的重点是实际上使功能setState安全的内容 但是您可以认为“排队”过程的结果是一系列函数,如下所示:

const updateQueue = [  (state) => ({score : state.score + 1}),  (state) => ({score : state.score + 1}),  (state) => ({score : state.score + 1})];

Finally, let’s fake the updating process:

最后,让我们伪造更新过程:

// recursively update state in the orderfunction updateState(component, updateQueue) {  if (updateQueue.length === 1) {    return component.setState(updateQueue[0](component.state));  }
return component.setState(    updateQueue[0](component.state),     () =>     updateState( component, updateQueue.slice(1))   );}
updateState(Justice, updateQueue);

True, this is not as so sexy a code. I trust you could do better. But the key focus here is that every time React executes the functions from your functional setState, React updates your state by passing it a fresh copy of the updated state. That makes it possible for functional setState to set state based on the previous state.

是的,这不是那么性感的代码。 我相信您可以做得更好。 但是这里的重点是,每次React从您的功能setState执行功能时 React都会通过向您传递状态的副本来更新您的状态。 这使功能setState可以根据先前的状态设置状态

Here I made a bin with the complete code. Tinker around it (possibly make it look sexier), just to get more sense of it.

在这里,我用完整的代码制作了一个bin。 修补它(可能会使它看起来更性感),只是为了使其更具感觉。

FunctionalSetStateInActionA Play with the code in this bin will be fun. Remember! we’re just faking React to get the idea...jsbin.com

FunctionalSetStateInAction 使用此bin中的代码进行播放会很有趣。 记得! 我们只是假装React来了解这个想法... jsbin.com

Play with it to grasp it fully. When you come back we’re gonna see what makes functional setState truly golden.

玩耍以充分掌握它。 当您回来时,我们将看到是什么使功能setState真正变成了黄金。

保留得最好的React秘密 (The best-kept React secret)

So far, we’ve deeply explored why it’s safe to do multiple functional setStates in React. But we haven’t actually fulfilled the complete definition of functional setState: “Declare state changes separately from the component classes.”

到目前为止,我们已经深入探讨了为什么在React中执行多个功能setState是安全的。 但是实际上我们还没有实现功能setState的完整定义:“声明状态更改与组件类分开。”

Over the years, the logic of setting-state — that is, the functions or objects we pass to setState() — have always lived inside the component classes. This is more imperative than declarative.

多年来,设置状态的逻辑(即,我们传递给setState()的函数或对象setState()一直存在组件类内部 。 这比声明性更重要。

Well today, I present you with newly unearthed treasure — the best-kept React secret:

好了,今天,我向您展示了新近发掘的宝藏- 保存最完好的React秘诀:

Thanks to Dan Abramov!

感谢Dan Abramov

That is the power of functional setState. Declare your state update logic outside your component class. Then call it inside your component class.

那就是功能setState的力量。 在组件类之外声明状态更新逻辑。 然后您的组件类中调用它。

// outside your component classfunction increaseScore (state, props) {  return {score : state.score + 1}}
class User{  ...
// inside your component class  handleIncreaseScore () {    this.setState( increaseScore)  }
...}

This is declarative! Your component class no longer cares how the state updates. It simply declares the type of update it desires.

这是声明性的! 您的组件类不再关心状态如何更新。 它只是声明所需的更新类型

To deeply appreciate this, think about those complex components that would usually have many state slices, updating each slice on different actions. And sometimes, each update function would require many lines of code. All of this logic would live inside your component. But not anymore!

要深深地体会到这一点,请考虑那些通常具有许多状态切片的复杂组件,并根据不同的操作更新每个切片。 有时,每个更新功能都需要很多代码行。 所有这些逻辑都将存在组件内部 。 但是现在不行了!

Also, if you’re like me, I like keeping every module as short as possible, but now you feel like your module is getting too long. Now you have the power to extract all your state change logic to a different module, then import and use it in your component.

另外,如果您像我一样,我希望每个模块的长度都尽可能短,但是现在您感觉模块太长了。 现在,您可以将所有状态更改逻辑提取到另一个模块,然后将其导入并在组件中使用。

import {increaseScore} from "../stateChanges";
class User{  ...
// inside your component class  handleIncreaseScore () {    this.setState( increaseScore)  }
...}

Now you can even reuse the increaseScore function in a different component. Just import it.

现在,您甚至可以在其他组件中重用gainScore函数。 只需导入即可。

What else can you do with functional setState?

您还可以使用setState功能做什么?

Make testing easy!

使测试变得容易!

You can also pass extra arguments to calculate the next state (this one blew my mind… #funfunFunction).

您还可以传递额外的参数来计算下一个状态(这使我震惊……#funfunFunction)。

Expect even more in…

期望更多……

React的未来 (The Future of React)

For years now, the react team has been experimenting with how to best implement stateful functions.

多年来,React团队一直在尝试如何最好地实现有状态功能

Functional setState seems to be just the right answer to that (probably).

函数setState似乎是正确的答案(可能)。

Hey, Dan! Any last words?

嘿,丹! 最后有话吗?

If you’ve made it this far, you’re probably as excited as I am. Start experimenting with this functional setState today!

如果到目前为止,您可能会像我一样兴奋。 开始尝试使用此功能setState 今天!

If you feel like I’ve done any nice job, or that others deserve a chance to see this, kindly click on the green heart below to help spread a better understanding of React in our community.

如果您觉得我做得很好,或者其他人值得一看,请单击下面的绿色心脏,以帮助在我们的社区中更好地理解React。

If you have a question that hasn’t been answered or you don’t agree with some of the points here feel free to drop in comments here or via Twitter.

如果您有未解决的问题,或者您不同意此处的某些观点,请随时在此处或通过Twitter发表评论。

Happy Coding!

编码愉快!

翻译自: https://www.freecodecamp.org/news/functional-setstate-is-the-future-of-react-374f30401b6b/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值