在 vue3 文档中,关于 provide 和 inject 的组件,官方有以下的说明
可以将依赖注入看作是“长距离的 prop”,除了:
父组件不需要知道哪些子组件使用了它 provide 的 property
子组件不需要知道 inject 的 property 来自哪里
所以一般来说,在composition-api中,我们使用会是
在父组件中注入
1 | <script setup lang="ts"> |
在父组件中注入
1 | <script setup lang="ts"> |
以上的使用是常规的做法,这样的话会有一个有选择的问题就是: 如果注入的state 是响应试的,那么在子组件中,就可以改变这个provide注入的值,
如果子组件都引用的情况下,都能改变,后期的代码就会不好维护。但如果state 不是响应式的,即provide(state)中state是一个普通对象时,那么
在父组件中如果当state改变时,子组件保证同步,从而丢失使用provide的意义。所以我们怎么选?
答案很明显,因为在ts中,我们可以使用readonly
修饰符来让注入的对象是响应式的,但是是只读的。这样子组件能及时响应到数据,而不能修改这个数据。
1 | // in provide |
1 | // in inject |
到了这一步,不可避免的就是在子组件中,使用这些数据,一定会涉及到这个数据的更应,不然,就没有意义了。所以,官方文档上提供了一种方式,
就是在注入的时候,同时提供一个注入的函数,用来改变state的值。即:
1 | // 父组件 |
1 | // 子组件 |
但是,如果只是这样,那么如果我们在不同组件中,都这么写,随着key的变多,就会非常不好维护。所以为了方便更好的使用(套娃)
我们需要** 多次 **封装一下 provide 及 inject
第一次封装,提供公有的 注入 和 使用的方法,并返回注入的对象,及改变对象的方法
1 | // useContext.ts |
以上这样包了一层后,那么我们上层调用就会变得简单了
1 | // 父组件中 |
1 | // 子组件中 |
到了这里,还没有完,因为这就涉及到在不同组件中写很多provide~, 所以我们需要针对不同的组件,再依赖于 createContext, useContext再包一层。
而且上面我们在createContext中,有三个参数,我需要针对第三个参数,对子组件提供出修改provideState的方法
比如 现在有一个layout组件,要注入一些主题,之类的那么我们可以建一个useLayoutContext.ts文件,
1 | import { MaybeRef } from '@vueuse/core' |
那么顶层组件 创建 provide 就可以
1 | const provideState = ref({}) |
而子组件中
1 | const { provideState, updateState } = useLayoutContextData() |
而在其它的组件里,同理。这样方便管理injectKey以及注入的 状态数据
其它
实现一个全局状态
只要把readonly去掉,让其在子组件中可以修改,就是全局状态管理 :) 是不是so easy!
- Post link: https://yuexiaoya.com/2021/12/15/frontend/vue3/Vue3%E4%B8%ADProvide-Inject%E8%BF%9B%E9%98%B6/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.