ZF_react dom-diff 新的生命周期,context上下文实现
Posted lin-fighting
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZF_react dom-diff 新的生命周期,context上下文实现相关的知识,希望对你有一定的参考价值。
dom-diff算法
如
ABCDEFG=>ACDBG
- 首先会有一个oldMap对象,存储老的键值对。
- 然后会有一个变量 lastPlaceIndex,表示上一个不需要移动的节点的位置(用来判断是否移动节点)
- 遍历新的虚拟DOM数组。
首先
新的虚拟dom第一个A,在oldMap中找到,位置为0,lastPlaceIndex标记为0,接着第二个C,在oldMap中找到,位置为2,lastPlaceIndex标记为2.
依次类推打B的时候,因为B在老的位置为1,跟LastPlaceIndex相比较小,所以不更新lastPlaceIndex。需要把B从1的位置移到新的3的位置。
到G的时候没有老节点,直接插入即可。在删除没有复用的节点EF。
这就是整体的移动过程。lastPlaceIndex的作用是,通过比对位置,判断是否挪动,如果比lastPalceIndex大,不挪动,如果小,就表示需要换位置。
Dom-diff算法先不详细开发。
新的生命周期
我们之前实现的
现在我们要实现新的生命周期
可以看到,
- 新的生命周期,没有componentWillMount,
- 而componentWillReceiveProps换成了getDerivedStateFromPorps(从props获取派生的状态)。
- 以及将componentWillUpdate换成了getSnapshotBeforeUpdate(在update之前获取快照(更新前dom的信息))
getDerivedStateFromProps的实现
- getDerivedStateFormProps是一个静态方法,只能通过类去调用,比如Son中有这个方法,只能通过Son.getDerivedState去调用。
- getDerivedStateFromPorps这个hooks可以返回一个新状态,用来代替即将更新的状态。比如应该更新的状态时{number:1},可以返回一个{number: 2}来替代。
- 这个方法的出现是为了替代componentWillReceiveProps,因为以前很多人在componentWillReeiveProps中使用this.setState来更改状态,导致了死循环。componetWillReceiveProps是在组件更新的时候由外部的props改变而引起的,所以他的调用位置,一般在处理新老子类组件的时候调用。
比shouldComponent更快调用。 - getDerivedStateProps的调用位置,他的目的是来修改最新的state。所以应该在新的state赋值给类实例的时候,也就是
在更改state之前,在shouldComponentUpdate之后实行。因为他的目的只是更改state。即使组件页面不更新,但组件实例也要更新上最新的state。
注意调用方法,是类.xxx去调用。看效果:
听过父组件的props加大自己的state数目。
顺便看下调用顺序。
getSnapShotBeforeUpdate的实现
在这个图片可以看出,getSnapShotBeforeUpdate是在render执行之后,dom更新之前执行的。可以在dom改变之前获取当前的dom(老的dom)
- getSnapShotBeforeUpdate可以返回一个对象,它将作为componentDidUpdate的第三个参数。
所以他的位置应该是在:
在render之后,在dom更新之前执行。这样在getSnapShotBeforeUpdate就能获取老的dom。如
效果
这样getSnapShotBeforeUpdate就完成了。
context的实现
在16版本以前,多次使用context会造成数据来源不清晰问题,而在16之后就解决了这个问题。如
// 16之前
let GrandFaterContext = {a: 1} //爷爷的Context
let FatherContext = {b:2} //父亲的context
let childContext = {...GranFatherContext, ...FatherContext} //类似的实现方式
childContext.a //?从哪里来的,不知道
在16之后,不再是合并,而是
// 16之后
let GrandFaterContext = {a: 1} //爷爷的Context
let FatherContext = {b:2} //父亲的context
let childContext = {GranFatherContext,FatherContext} //类似的实现方式
childContex.GranFatherContextt.a //从爷爷来,清晰可见。
接着开始实现context的代码,不多,
将状态从父组件传入context,先实现类组件。
类组件通过定义一个静态属性就可以通过this,context获取上下文信息。
效果:
可以看到color可以贯穿,并且可以在子组件发送事件对context的内容进行修改。
实现思路:
先看createContext
可以看到返回的就是一个对象,里面有Provider,Consumer以及一个_value属性,用来存放context的state。
类组件是通过定义静态类型contextType,从而让this.context获取到值。在第一次render的时候就要用到this.context,所以我们必须在render之前判断
type指向的就是Son这个类,如果这个类有这个静态属性,则赋值实例的context属性,值就是
所以
classInstance.context = React.createContext()._value
就是这样获取context的状态的。
然后更改的时候,context的state发生了变化,此时context需要重新赋值,思路依然是在render之前调用。也就是
在下一次组件重新render之前赋值最新的context。这样就实现了类组件的context。
接着实现函数组件的context。
先看如何使用:
实现也很简单,传入对应的value即可。看效果:
可以看到函数组件可以正常拿到context的值,
以上是关于ZF_react dom-diff 新的生命周期,context上下文实现的主要内容,如果未能解决你的问题,请参考以下文章
ZF_react react-router prompt lazy的实现