浅学一下 --- Vue 组合式函数

122 阅读3分钟

官网地址:cn.vuejs.org/guide/reusa…

“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。

有状态逻辑的函数:请记住这 有状态逻辑 5个字

无状态逻辑的函数:即平常抽离出的那些可复用的函数

个人认为:其实就是普通函数。正常的普通函数调用就是了,只不过里面的变量用 reactive/ref 等包装过后就可以用在模板和其他watch的钩子函数。

为什么会出现 “组合式函数”

Vue2 关于代码的复用使用的是 mixins。而 mixins 存在如下问题:

  1. 不清晰的数据来源:当使用多个 mixins 时,确切知道数据属性来自哪个 mixin 变得困难。

    // 定义一个名为 mixinA 的 mixin
    const mixinA = {
      data() {
        return {
          message: 'Mixin A',
        };
      },
    };
    
    // 定义另一个名为 mixinB 的 mixin
    const mixinB = {
      data() {
        return {
          message: 'Mixin B',
        };
      },
    };
    
    // 使用两个 mixin
    new Vue({
      mixins: [mixinA, mixinB],
      created() {
        console.log(this.message); // 这里不清楚 `message` 属性来自哪个 mixin
      },
    });
    
  2. 命名空间冲突:多个 mixin 可能会注册相同的属性名,导致命名冲突

    // 定义一个名为 mixinA 的 mixin
    const mixinA = {
      data() {
        return {
          message: 'Mixin A',
        };
      },
    };
    
    // 定义另一个名为 mixinB 的 mixin,不知不觉中重复了属性名
    const mixinB = {
      data() {
        return {
          message: 'Mixin B',
        };
      },
    };
    
    // 使用两个 mixin
    new Vue({
      mixins: [mixinA, mixinB],
      created() {
        console.log(this.message); // 这里的 `message` 冲突了
      },
    });
    
  3. 隐式的跨 mixin 交流:多个 mixin 需要依赖共享的属性名进行相互作用,这使得它们隐式地耦合在一起。

    // 定义 mixinA,依赖另一个 mixinB 的属性
    const mixinA = {
      computed: {
        reversedMessage() {
          return this.message.split('').reverse().join('');
        },
      },
    };
    
    // 定义 mixinB,提供一个属性
    const mixinB = {
      data() {
        return {
          message: 'Hello from mixin B',
        };
      },
    };
    
    // 使用两个 mixin,mixinA 隐式依赖 mixinB 的属性
    new Vue({
      mixins: [mixinA, mixinB],
      created() {
        console.log(this.reversedMessage); // mixinA 隐式依赖 mixinB 的属性
      },
    });
    

那来看看 Vue 的组合式函数是如何解决上面出现的三种问题?

  1. 不清晰的数据来源:在组合式函数中,可以通过使用 ref 和解构模式明确指定数据属性的来源。

    import { ref } from 'vue';
    
    function useMixinA() {
      const message = ref('Mixin A');
      return { message };
    }
    
    function useMixinB() {
      const message = ref('Mixin B');
      return { message };
    }
    
    // 在组件中使用组合式函数
    export default {
      setup() {
        const { message: messageA } = useMixinA();
        const { message: messageB } = useMixinB();
        console.log(messageA.value); // 明确知道来自 useMixinA
        console.log(messageB.value); // 明确知道来自 useMixinB
      },
    };
    
  2. 命名空间冲突:组合式函数允许将属性明确命名,避免不同 mixin 之间的属性名冲突。

    function useMixinA() {
      const messageA = ref('Mixin A');
      return { messageA };
    }
    
    function useMixinB() {
      const messageB = ref('Mixin B');
      return { messageB };
    }
    
    // 在组件中使用组合式函数
    export default {
      setup() {
        const { messageA } = useMixinA();
        const { messageB } = useMixinB();
        console.log(messageA.value); // 不会冲突
        console.log(messageB.value); // 不会冲突
      },
    };
    
  3. 隐式的跨 mixin 交流:组合式函数可以更明确地处理不同函数之间的交流,可以将一个组合式函数的返回值作为另一个组合式函数的参数传递,从而更清晰地定义和管理依赖关系。

    function useMixinA(message) {
      const reversedMessage = computed(() => message.value.split('').reverse().join(''));
      return { reversedMessage };
    }
    
    function useMixinB() {
      const message = ref('Hello from mixin B');
      return { message };
    }
    
    // 在组件中使用组合式函数
    export default {
      setup() {
        const { message } = useMixinB();
        const { reversedMessage } = useMixinA(message);
        console.log(reversedMessage.value);
      },
    };