基于React 源码深入浅出setState:官方文档的启示录

作者:墨成

React版本 :16.4.1

仔细阅读官网setState的描述会发现里面透露的信息量巨大,我也建议初学者在学习React之前仔细阅读原始文档,以下是我个人在阅读文档时的一些领悟,配合了一些翻译和讲解,限于个人水平,不足之处,各位请多多指出

setState(updater[, callback])

setState()enqueueschanges to the component state and tells React that this component and itschildren need to be re-rendered with the updated state. This is the primarymethod you use to update the user interface in response to event handlers andserver responses.

翻译:  setState()通过队列的形式保存组件状态并告诉React这个组件和他的子组件需要重新渲染。这是我们通过事件或服务器响应更新用户接口的主要方法(也就是说我们最常用)

解释:无

Think

of setState()as arequest rather than an immediate command to update the component. For betterperceived performance, React may delay it, and then update several componentsin a single pass. React does not guarantee that the state changes are appliedimmediately.

翻译: setState()只是作为一个请求而不是一个立刻执行的指令去更新组件。为了更好的性能,React会延迟执行,然后通过一种单一(这个单一在这里的意思是归类的意思)的方式去更新几个组件。React不会立刻把state的改变应用到组件上

解释:这句的话的意思很明显就是告诉你: React的 setState是"异步"的,React在没有重新渲染之前对state的做了一些处理以达到最佳的性能

setState() does not

always immediately update the component. It may batch or defer the update until

later. This makes reading this.state right

after calling setState() a

potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater,

callback)), either of which are guaranteed to fire after the update has

been applied. If you need to set the state based on the previous state, read

about the updaterargumentbelow.

翻译: setState()并不总是立刻更新组件(言下之意就是有办法可以立刻更新,后面会讲道这部分内容)。随后它会使用批处理或延迟更新 。在你调用setState()后立刻读取 this.state的值不会生效(原文叫 潜在的陷阱)。相反,使用componentDidUpdate或者  setState回调函数 的任意一种方式都会让对state的更新生效(原文的作者使用了fire这个词非常形象,想象一下这样的一种场景:你为了一个难题彻夜难眠,绞尽脑汁,突然看到了火(黑暗前的黎明,激动)是希望!!).如果你想基于上一个state来设置state,请阅读下方updater的参数

解释:setSate虽然是异步的,但是我们还是可以通过其他方式读取到生效的值,比如在react生命周期函数 componentDidUpdate和 setState的回调函数中读取

。言下之意是告诉我们在 setState完成后,会激活 componentDidUpdate周期函数,有回调函数会执行回调函数。

[if !supportLineBreakNewLine]

[endif]


setState() will

always lead to a re-render unless shouldComponentUpdate() returns false. If mutable

objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState()only whenthe new state differs from the previous state will avoid unnecessaryre-renders.

翻译: setState总是会触发重渲染,除非shouldComponentUpdate()返回 false .shouldComponentUpdate()不应该包含可变对象作为条件渲染的逻辑,我们仅仅在state发生变化去调用setSate而避免不必要的重新渲染

解释:shouldComponentUpdate()的逻辑中不可以直接用不稳定对象的值作为返回值,就是说对于引用类型,地址总是相同,返回值永远为true(浅比较).


The

first argument is an updaterfunction with the signature:

(prevState, props) => stateChange

prevState is a

reference to the previous state. It should not be directly mutated. Instead,

changes should be represented by building a new object based on the input from prevStateand props. For instance,

suppose we wanted to increment a value in state by props.step:

翻译:prevState 是上一个状态的引用.它不应该直接被改变。这种变化应该是基于prevState和 props构建的一个新对象。比如,假如我们想在state中通过props.step去对一个值做增量操作:

解释:无

this.setState((prevState, props) => {

  return {counter: prevState.counter + props.step};

});

Both prevState and props received

by the updater function are guaranteed to be up-to-date. The output of the

updater is shallowly merged with prevState.

翻译: updater

function保证接受到的prevState和props是最新的(这里的最新是相对于上次 render后的值,而不是连续调用setState的值,这里可能会让有些人有点误解)。调用updater function是浅合并(这里有故事)

解释:无

The

second parameter to setState() is an

optional callback function that will be executed once setState is

completed and the component is re-rendered. Generally we recommend using componentDidUpdate()for suchlogic instead.

翻译:第二个是可选的回调函数,它会在setState完成后并且组件重新渲染后立刻执行。一般来说,我们推荐使用componentDidUpdate()来替换这个逻辑。

解释:如果使用回调函数,React更建议在componentDidUpdate来处理这个逻辑。就是这个回调函数在没有特别必要的情况下不要使用(源码对callback做了很多逻辑处理,后面也会提及)

You

may optionally pass an object as the first argument to setState()instead ofa function:

setState(stateChange[, callback])

翻译:你可以有选择性的传递一个对象作为setState的第一参数

解释:除了传递函数之外也可以使用对象作为参数

This

performs a shallow merge of stateChangeinto thenew state, e.g., to adjust a shopping cart item quantity:

this.setState({quantity: 2})

翻译:它会执行浅合并来生成一个新的state,比如说:修改购物车里的商品数量

This

form of setState()is alsoasynchronous, and multiple calls during the same cycle may be batched together.For example, if you attempt to increment an item quantity more than once in thesame cycle, that will result in the equivalent of:

Object.assign(

  previousState,

  {quantity: state.quantity + 1},

  {quantity: state.quantity + 1},

  ...

)

翻译:这种形式的setState()(把对象作为参数)也是"异步"的,相同周期(这个cycle的翻译我还没找到合适的词,暂且使用周期,比如同一个函数多次调用setState,我们就认为他们在同一个周期)的多次调用会被批量执行。比如,如果你试图在同一周期多次增加商品的数量,那么它的结果等同于:

解释:这里的例子非常关键,要理解它必须完全理解Object.assign合并对象的原理,比如说,不同对象相同属性,后面的对象会覆盖前面的对象;不同对象不同属性,会合并到最终的对象上


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

this.setState((prevState) => {

  return {quantity: prevState.quantity + 1};

});

翻译:在同一周期靠后的setState()将会覆盖前一个setSate()的值(相同属性名),因此,这个商品数量仅自增了一次,如果希望下一个state依赖上一个state,我们推荐使用函数的形式

解释:这里很明显的告诉我们,setSate第一参数传递的对象或函数,react的处理方式不一样, 这跟React在性能优化有很大关系,为了最小可能性去re-render(重渲染),React源码作了很多额外的工作


至此,官方文档对setState()的概要描述已经结束

后面我会对官方的文档的解释写一些demo来验证

同时随着理解的深入,后面会不断对源码进行解析

未完待续..........

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容