持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情
前言
在开发中,我们构建了组件树之后,除了父子组件之间的通信之外,还会有非父子组件之间的通信。
这篇文章记录一下 Provide/Inject 的使用
使用场景
用于非父子组件之间共享数据,比如有一些深度嵌套的组件,子组件想要获取父组件的部分内容,在这种情况下,如果我们仍然将props沿着组件链逐级传递下去,就会非常的麻烦,这种情况,我们可以使用Provide 和 Inject
- 无论层级结构有多深,父组件都可以作为其所有子组件的依赖提供者;
- 父组件有一个 provide 选项来提供数据;
- 子组件有一个 inject 选项来开始使用这些数据;
局限: Provide只限于父组件提供数据,子孙组件使用Inject获取,兄弟组件之间无法通过 Provide/Inject 传递数据,常用来传递简单数据,复杂数据多使用Vuex或Pinia
基本使用
当我们需要开发一个这样的结构:App组件中有 Home组件 Home组件中有HomeContent组件
通过 provide 在父组件App.vue中注册数据,通过inject在子组件的子组件(孙组件)中拿到传递过来的数据
Vue2
如果Provide中提供的一些数据是来自data,那么我们可能会想要通过this来获取:
不出意外,这个时候this会报错,此时this指向是undefind,这时我们把provide写成一个函数 返回对象的形式,这时 this 会绑定 provide函数中的this,而provide函数中的this在执行时会绑定组件实例从而找到data中的数据
处理响应式数据
我们先来验证一个结果:如果我们修改了this.names的内容,那么使用length的子组件会不会是响应式的?
绑定一个点击事件点击改变 names 的长度,console会发现names数组确实改变了,但是provide中 this.names.length没有发生变化。
这是因为当我们修改了names之后,之前在provide中引入的 this.names.length 本身并不是响应式的;
那如何才能让this.names.length跟着变化呢?
-
我们可以provide 一个函数,将其 return 出去给子孙组件用,这样子孙组件每次拿到的数据才会是新的。
但由于不具备响应性,所以子孙组件每次都需要重新通过执行
inject得到的函数才能拿到最新的数据。 -
调用Vue3 API computed
Vue3
Vue3 的新版 provide/inject, 和 Vue2 的用法区别比较大。
- 在 Vue3 , provide/inject 需要导入并在 setup 里启用,并且现在是一个全新的方法。
- 每次要 provide/inject 一个数据的时候,就要单独调用一次。
处理响应式数据
Vue3中 provide 和 inject 本身也不可响应,如果要使其具备响应性,需要传入响应式数据。
可利用响应式API
ref,reactive
computed(本质 ref 对象)
响应式的数据 provide 出去,在子孙组件拿到的也是响应式的,并且可以如同自身定义的响应式变量一样,直接 return 给 template 使用,一旦数据有变化,视图也会立即更新。
但上面这句话有效的前提是,不破坏数据的响应性,比如 ref 变量,需要完整的传入,而不能只传入它的 value,对于 reactive 也是同理,不能直接解构去破坏原本的响应性。
切记!切记!!!