Vue3中provide-inject的实现

442 阅读2分钟

前言

  • provide和inject就是为了实现跨级通信,比如在组件库中,想跨级通信,那么就可以采用provide/inject
  • 在vue3中,provide和inject只能在setup中使用
  • 所有的compositionAPI都要以setup为入口

使用示例

Image.png

实现

  • 实现原理是在父组件上增加了一个provide属性,当调用provide的时候会向属性中存值
  • 在渲染子组件的时候,子会将父的provide放到自己的身上
  • 就不像vue2那样递归查找了

我们现在要做的事情是维系组件间的父子关系

在核心方法patch中加一个参数parentComponent

Image.png

我们在处理元素、Fragmant和组件的时候把这个parentComponent带过去

Image.png

  • 因为元素里面可能会渲染一个组件,Fragment里面也可能渲染一个组件,组件里面更可能会渲染一个组件,所以我们把这三种情况的处理,把parentComponent都带过去

处理Fragment

Image.png

  • 在挂载儿子的时候把parentComponent传过去
  • 更新的时候就不用管了

mountChildren里把parentComponent继续传到patch中

Image.png

挂载子元素时

Image.png

比较孩子的时候,挂载的孩子的时候也需要传入parentComponent

Image.png

Image.png

更新儿子的时候也要加

Image.png

靶向更新的时候也要传

Image.png

处理元素的时候

Image.png

处理组件的时候同理,流程中都要把parentComponent传入

Image.png

当创建组件实例的时候,我们要知道组件的爸爸是谁,这里是最核心的

Image.png

Image.png

至此,父子组件的关系我们就构建好了

下一次再渲染的时候,渲染subTree的时候,它的父亲就是组件实例

Image.png

组件更新的时候同理

Image.png

总结

  • 我们就是根据渲染流程,先渲染父后渲染子的顺序关系,来构建出它们的父子关系

我们在组件实例上增加provides属性

Image.png

  • 如果parent有值,去父亲上的provides
  • 这样所有的组件用的都是父亲的provides

在runtime-core中闯将apiinject.ts来实现provide、inject两个api

provide方法

Image.png

  • 判全局上currentInstance是否有值,在setup中才会往这个全局变量上赋值,这也就保证了provide一定要用到setup语法中
  • 拿到自己的provides,拷贝一份,赋值到当前的provides, 但是这样会消耗性能,所以我们先取父亲的provides和自己的provides,如果它俩相当,那么说明是第一次渲染,我们就去做这次拷贝操作,后续的渲染我就们直接拿上次的拷贝结果就可以了

inject方法

Image.png

  • 同样判断当前组件实例是否存在,来保证这个api一定在setup中使用
  • 拿到父亲的provides,判断key是否能存在于父亲的provides中,如果存在就返回回去

解释一下为什么通过currentInstance来判断是否是在setup中使用

Image.png

inject其实还有第二个参数defaultValue

Image.png