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的值,

Guess you like

Origin blog.csdn.net/lin_fightin/article/details/120879078
Recommended