【Vue】依赖注入

Vue2 写法

用于祖先组件给后代组件传递数据:
① 在祖先组件中配置 provide,指定需要传递的数据(provide 用法类比 data
② 在后代组件中配置 inject,并接收数据(inject 用法类比 props

  • provide 有两种写法:
    对象式写法:只能传递静态信息,不能获取 this
    函数式写法:可以获取并传递 this 的信息,this 指向当前组件实例
  • provide 会被代理成 _provide,我们可以通过 this._provide.属性名 在父组件中获取 provide 对象的属性
  • 注意:在后代组件中,不建议修改祖先组件传递下来的数据
<template>
    <div>
        <button @click="showPro">点击获取 provide 的属性信息</button>

        <hr />
        <Son />
    </div>
</template>

<script>
import Son from './components/Son.vue';

export default {
      
      
    name: 'App',
    components: {
      
       Son },
    data() {
      
      
        return {
      
       msg: 'app 组件的数据' };
    },
    /* 配置 provide */
    // 函数式写法,可以通过 this 访问当前组件
    provide() {
      
      
        // 设置需要传递的数据
        return {
      
       childMsg: this.msg };
    },
    // 对象式写法,只能传递静态数据
    // provide: { childMsg: "静态数据" },
    methods: {
      
      
        showPro() {
      
      
            // 我们可以通过 this._provided 获取 provide 的对象数据
            console.log('provide 对象数据', this._provided);
        },
    },
};
</script>
<template>
    <div class="son">
        <p>inject:{
   
   { childMsg }}</p>
    </div>
</template>

<script>
export default {
      
      
    name: 'Son',
    inject: ['childMsg'], // 配置 inject、 接收祖先组件传递的数据
};
</script>



Vue3 写法

  • 为后代组件提供数据:provide(key, value)
    • key 可以为 String / Symbol ; value 可以为任意类型,包括响应式的状态
    • 提供的响应式状态使后代组件可以由此和提供者建立响应式的联系
  • 注入上层组件提供的数据:inject(key[, 默认值])
    • 如果提供的值是一个 ref,注入进来的会是该 ref 对象,而不会自动解包为其内部的值。这使得注入方能够通过 ref 对象保持和供给方的响应式链接
    • 在一些场景中,默认值可能需要通过调用一个函数或初始化一个类来获取。为避免在用不到默认值的情况下进行不必要的计算或产生副作用,我们可以使用工厂函数来创建默认值,eg: inject(key, () => new ExpensiveClass())
<template>
    <HelloWorld />
    <button @click="textDemo += '~'">update</button>
</template>

<script lang="ts" setup>
import {
      
       ref, provide } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue';

const textDemo = ref('Vue.js');

provide('title', textDemo);
</script>
<template>
    {
   
   { val }}
</template>

<script lang="ts" setup>
import {
      
       inject } from 'vue';

const val = inject('title', '默认值');
</script>

和响应式数据配合使用

当 provide / inject 响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护

有的时候,我们可能需要在注入方组件中更改数据。在这种情况下,我们推荐在供给方组件内声明并提供一个更改数据的方法函数:

<template>
    <HelloWorld />
    <button @click="textDemo += '~'">update</button>
</template>

<script lang="ts" setup>
import {
      
       ref, provide } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue';

const textDemo = ref('Vue.js');

const updateTitle = (val: string) => {
      
      
    textDemo.value += val;
};

provide('title', {
      
       textDemo, updateTitle }); // 提供依赖及更新依赖的方法
</script>
<template>
    <button @click="updateTitle('+')">update</button>
    {
   
   { textDemo }}
</template>

<script lang="ts" setup>
import {
      
       inject } from 'vue';

const {
      
       textDemo, updateTitle } = inject<any>('title'); // 注入依赖及更新依赖的方法
</script>
  • 如果想确保提供的数据不能被注入方的组件更改,可以使用 readonly() 来包装提供的值
    eg: provide('read-only-count', readonly(count))
  • readonly() 接收一个对象 ( 不论是响应式还是普通 ) ,返回一个原值的只读代理

使用 Symbol 作注入名

推荐在一个单独的文件中导出这些 Symbol 注入名

// keys.js
import type {
    
     InjectionKey } from 'vue';
export const myInjectionKey = Symbol() as InjectionKey<string>;
// 在供给方组件中
import {
    
     provide } from 'vue';
import {
    
     myInjectionKey } from './keys.js';

provide(myInjectionKey, {
    
    
    /* 要提供的数据 */
});
// 在注入方组件中
import {
    
     inject } from 'vue';
import {
    
     myInjectionKey } from './keys.js';

const injected = inject(myInjectionKey);

应用层 Provide

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

import {
    
     createApp } from 'vue';

const app = createApp({
    
    });

app.provide('message', 'hello!');



猜你喜欢

转载自blog.csdn.net/Superman_H/article/details/128836243