【Provide/Inject】数据传递知多少

775 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

前言

在开发中,我们构建了组件树之后,除了父子组件之间的通信之外,还会有非父子组件之间的通信。

这篇文章记录一下 Provide/Inject 的使用

使用场景

用于非父子组件之间共享数据,比如有一些深度嵌套的组件,子组件想要获取父组件的部分内容,在这种情况下,如果我们仍然将props沿着组件链逐级传递下去,就会非常的麻烦,这种情况,我们可以使用Provide 和 Inject image.png

  • 无论层级结构有多深,父组件都可以作为其所有子组件的依赖提供者;
  • 父组件有一个 provide 选项来提供数据;
  • 子组件有一个 inject 选项来开始使用这些数据;

局限: Provide只限于父组件提供数据,子孙组件使用Inject获取,兄弟组件之间无法通过 Provide/Inject 传递数据,常用来传递简单数据,复杂数据多使用Vuex或Pinia

基本使用

当我们需要开发一个这样的结构:App组件中有 Home组件 Home组件中有HomeContent组件

image.png

通过 provide 在父组件App.vue中注册数据,通过inject在子组件的子组件(孙组件)中拿到传递过来的数据

Vue2

image.png

如果Provide中提供的一些数据是来自data,那么我们可能会想要通过this来获取:

不出意外,这个时候this会报错,此时this指向是undefind,这时我们把provide写成一个函数 返回对象的形式,这时 this 会绑定 provide函数中的this,而provide函数中的this在执行时会绑定组件实例从而找到data中的数据

image.png

处理响应式数据

我们先来验证一个结果:如果我们修改了this.names的内容,那么使用length的子组件会不会是响应式的?

image.png

绑定一个点击事件点击改变 names 的长度,console会发现names数组确实改变了,但是provide中 this.names.length没有发生变化。

这是因为当我们修改了names之后,之前在provide中引入的 this.names.length 本身并不是响应式的;

那如何才能让this.names.length跟着变化呢?

  1. 我们可以provide 一个函数,将其 return 出去给子孙组件用,这样子孙组件每次拿到的数据才会是新的。

    但由于不具备响应性,所以子孙组件每次都需要重新通过执行 inject 得到的函数才能拿到最新的数据。

    image.png

  2. 调用Vue3 API computed

    image.png

Vue3

Vue3 的新版 provide/inject, 和 Vue2 的用法区别比较大。

  • 在 Vue3 , provide/inject 需要导入并在 setup 里启用,并且现在是一个全新的方法。
  • 每次要 provide/inject 一个数据的时候,就要单独调用一次。

image.png

image.png

处理响应式数据

Vue3中 provide 和 inject 本身也不可响应,如果要使其具备响应性,需要传入响应式数据。

可利用响应式API

ref,reactive

image.png

computed(本质 ref 对象)

image.png

响应式的数据 provide 出去,在子孙组件拿到的也是响应式的,并且可以如同自身定义的响应式变量一样,直接 return 给 template 使用,一旦数据有变化,视图也会立即更新。

但上面这句话有效的前提是,不破坏数据的响应性,比如 ref 变量,需要完整的传入,而不能只传入它的 value,对于 reactive 也是同理,不能直接解构去破坏原本的响应性。

切记!切记!!!