React Virtual Dom 二三事
React 及Angular 中都有VD 一说,他们是用来组织他们的组件,负责计算差别,然后将这些差异更新到Dom树上面。VD 于Dom他们的节点是一一对应的,但是他们的结构却是不一定一样。
- 如何创建一个VD 节点,也就是ReactNode,
- 第一种方法,jsx 或者调用React.createElement(), 这样就可以创建一个了一个ReactNode, 然后我们可以将这个节点放置到React VD 树上了,
- 如何将这个节点放置到树上,两种方式,第一个,如何我们已经有了一个VD的引用(例如,我们在一个组件的render方法里面,)那么我们可以直接将我们创建的节点作为这个引用的一部分,也就是说,我们创建的节点作为render 方法返回的一部分。第二个,如果没有这样的VD引用,那么我们可以直接调用React.render(ReactNode,htmlElement),那么我们就重新又创建了一颗React VD的子树,htmlElement,标记,我们的节点在这个htmlelement下面构建。
同学们,第一个方法是我们经常用的方法,我们经常以这种方式来写我们的业务逻辑,第二个方法,其实是我们App的主树,如果看一下我们的index.tsx,这个里面就会有这个方法,但是呢,我们可以用第二个方法凭空创建出一个ReactNode,然后呢,我们可以把它交给React,它负责给我们渲染更新到Dom树上了 - 再次强调一下React.render(ReactNode,htmlElement)这个方法的强大之处,它可以让我们非常*的通过编程的方式,而不是通过React组件树的方式来添加一个节点。(有同学可能会问,这个有啥用,通过传统的方式,最大的限制就是我们得有一个爹,我们得有一个父亲节点,我们才能添加一个元素,有时候呢,我们可能处在VD树的一个很深的节点,然后我们希望展现一个通用组件,我不想在这个当前这个组件里面再次定义这个通用组件,一来是代码冗余,二来这样写代码太累)。这样一来这个方法就给我们提供了一种方案,非常的爽。
- 实战一下,Antd/rc里面有个Notification的组件,它有两种用法,一种就是弹出一个Dialog,里面的内容你自己参数传进去, 这种模式下,弹框里面的内容跟当前的调用组件完全无关,他们分别在两个不同的VD树上。第二种方法,useNotification()hook函数的方法,这个方法则是,Dom树完全隔离,VD树,你的内容部分跟调用者待在一起,有个很大的特点就是接收Context。
- 这边有个坑,我之前理解是,既然内容部分跟调用者在一起VD上,那么它就参与了调用者的刷新。然后我发现事实并非如此。第一,内容部分却是跟调用者在一起,第二,但是调用者setState(),它的土著内容却是刷新了,但是,notification的内容部分确没有刷新。为什么???,因为内容部分不是由调用者创建的,它是由外部传递进来的,所以当render方法再次调用时,这部分内容压根就没有变化过,所以,React 肯定不会触发setState,刷新内容部分。相当于内容部分是使用了React.memo(),或者是存放在了Ref里面一样。
- 这时我们可以得出几个结论,React 再做diff的时候,会先