vue3深入组件——依赖注入

一、场景介绍:一般父子间信息传递是通过props,但是一个多层嵌套的组件,必须将其沿着组件逐级的传递下去,这就是props的逐级透传。

 

二、上述情况下,就需要用到provide 和 inject;一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。


1、为后代组件提供数据,需要使用Provide (提供)
provide('name', 'Info')
第一个参数是注入名:可以是字符串也可以是symbol,后代通过注入名查找期望的值
第二个参数是提供的值,值可为任意类型,包括响应式的状态——ref
 
<script setup>
import {ref, provide } from 'vue'
const count =ref(0);
provide('key', count)
</script>
//提供的响应式状态,使后代组件由此和提供者建立响应式联系




// 如果没有使用<script setup>,需在 setup() 同步调用
<script>
    import { provide } 'vue'
    setup(){
        provide(/*注入名*/'message',/*值*/ 'hello')
    }
</script>
2、应用层的provide:除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖:
import { createApp } from 'vue'

const app = createApp({})

app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')

// 在应用级别提供的数据在该应用内的所有组件中都可以注入

二、注入(inject):要注入上层组件提供的数据,需使用 inject() 函数

<script setup>
    import { inject } from 'vue'
    const message = inject('message')
<script>

// 如果提供的是一个ref,注入进来的也是ref对象,不易自动解包为其内部的值,这使得注入方组件可以通过ref对象和提供方保持响应式链接

<script>
    import { inject } 'vue'
    setup(){
        const message = inject('message')
        return { message }
    }
</script>
2.1、注入默认值:如果注入名没有任何组件提供,会抛出一个运行时警告,如果注入一个值时,不必须有提供者,应该声明一个默认的,和 props 类似
// 如果没有祖先组件提供 "message"
// `value` 会是 "这是默认值"
const value = inject('message', '这是默认值')

有些情况默认值可能需要调用一个函数或者初始化一个类来获取,为了避免用不到默认值的情况下进行不必要的计算或者产生副作用,可以使用工厂函数,来创建默认值

const value = inject('key', () => new ExpensiveClass(), true)

第三个参数表示默认值应该被当作一个工厂函数。

三、和响应式数据配合使用

### Vue3 依赖注入的使用方法与示例 #### 提供依赖 (Provide) 在 Vue3 中,`provide()` 方法用于向上层组件提供数据或功能。这些提供的内容可以通过 `inject()` 在下级组件中获取。 以下是通过 `provide()` 向整个应用程序提供全局变量的例子: ```javascript // main.js import { createApp } from &#39;vue&#39;; import App from &#39;./App.vue&#39;; const app = createApp(App); // 提供一个名为 &#39;appMessage&#39; 的全局变量 app.provide(&#39;appMessage&#39;, &#39;Hello from Vue App!&#39;); app.mount(&#39;#app&#39;); ``` 在这个例子中,`app.provide(&#39;appMessage&#39;, &#39;Hello from Vue App!&#39;)` 将字符串 `&#39;Hello from Vue App!&#39;` 注入到整个应用上下文中[^2]。 如果需要更复杂的对象作为依赖项,则可以在供给方组件中定义并传递该对象: ```javascript // ParentComponent.vue <script> import { provide, reactive } from &#39;vue&#39;; export default { setup() { const state = reactive({ count: 0, increment() { state.count++; }, }); // 提供状态给子组件 provide(&#39;state&#39;, state); return {}; } }; </script> ``` 在此代码片段中,我们创建了一个响应式的 `state` 对象,并将其通过 `provide()` 方法共享给后代组件[^1]。 #### 获取依赖 (Inject) 相对应地,在任何后代组件中都可以利用 `inject()` 来访问由父辈组件所提供的资源。下面展示如何接收上述提到的状态信息: ```html <!-- ChildComponent.vue --> <template> <div> Count is: {{ state.count }} <button @click="increment">Increment</button> </div> </template> <script> import { inject } from &#39;vue&#39;; export default { setup() { const state = inject(&#39;state&#39;); function increment() { state.increment(); } return { state, increment }; } }; </script> ``` 这里展示了如何从上级组件引入已有的 `state` 并调用其内部的方法来改变数值[^4]。 另外需要注意的是,当使用 TypeScript 开发时,为了获得更好的类型支持和错误提示,推荐为键名指定特定类型的常量而不是简单的字符串字面量。例如: ```typescript // keys.ts import { InjectionKey } from &#39;vue&#39;; export const MyStateSymbol: InjectionKey<MyType> = Symbol(); function useProvider() { provide(MyStateSymbol, someValue as MyType); } function useInjector() { const value = inject(MyStateSymbol)!; } ``` 这种方式不仅提高了可维护性和安全性,还使得重构变得更加容易[^3]。 #### 注意事项 - **单向数据流动**:虽然能够向下传播属性,但是不应该尝试去更改来自上层的数据副本——这违背了 Vue 的设计理念之一即保持清晰的一致性模型。 - **性能考量**:过度频繁或者复杂度高的依赖关系可能会影响渲染效率;因此建议仅限于必要场合才采用此技术手段。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值