Vue 3 Composition API与Hooks模式

Vue 3 的 Composition API 引入了 Hook 函数的概念,这是一种更加模块化和可重用的状态管理和逻辑组织方式。

自定义Hook

首先,我们创建一个自定义 Hook,例如 useCounter,它封装了计数器的逻辑:

javascript 复制代码
// useCounter.js
import { ref } from 'vue';

export function useCounter() {
  const count = ref(0);

  function increment() {
    count.value++;
  }

  function decrement() {
    count.value--;
  }

  return {
    count,
    increment,
    decrement
  };
}

在上面的代码中,ref 用于创建响应式数据,incrementdecrement 方法分别用于增加和减少计数器的值。return 语句暴露了可以被组件直接使用的数据和方法。

然后,在组件中,我们可以导入并使用这个 Hook:

javascript 复制代码
<template>
  <div>
    <h1>Count: {{ count }}</h1>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useCounter } from './useCounter';

export default defineComponent({
  setup() {
    const { count, increment, decrement } = useCounter();

    return {
      count,
      increment,
      decrement
    };
  }
});
</script>

在组件的 setup 函数中,我们调用了 useCounter Hook 并将返回的对象解构赋值给局部变量。这些变量可以直接在模板中使用,因为它们都是响应式的。

这种模式的好处在于:

  1. 逻辑分离:Hook 可以封装特定的业务逻辑,使得组件代码更清晰,更容易维护。
  2. 复用性:Hook 可以在多个组件之间共享,减少代码重复。
  3. 类型安全:在 TypeScript 中,自定义 Hook 可以提供类型定义,提高代码的可读性和可预测性。
  4. 响应式系统:通过 ref 或 reactive 创建的响应式数据,可以确保状态变化时视图的自动更新。

Vue 3 的 Composition API 结合 Hook 模式,使得开发者能够更灵活地组织和重用代码,提高了代码的可维护性和开发效率。

内置Hook

除了自定义 Hook,Vue 3 的 Composition API 还提供了许多内置 Hook,如 watch, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, toRefs, computed, watchEffect 等。

1. onMounted: 当组件挂载完成后执行的钩子。

javascript 复制代码
import { onMounted } from 'vue';

export default {
  setup() {
    let element;

    onMounted(() => {
      element = document.querySelector('#someElement');
      // 在这里可以执行依赖于DOM的初始化操作
    });

    return {};
  }
};

2. computed: 计算属性,类似于 Vue 2 中的计算属性。

javascript 复制代码
import { ref, computed } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    const result = computed(() => {
      return base.value * multiplier.value;
    });

    return {
      base,
      multiplier,
      result
    };
  }
};

3. watch: 监听响应式数据的变化。

javascript 复制代码
import { ref, watch } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    watch(base, (newBase, oldBase) => {
      console.log(`Base changed from ${oldBase} to ${newBase}`);
    });

    return {
      base,
      multiplier
    };
  }
};

4. watchEffect: 在任何依赖改变时运行的副作用函数。

javascript 复制代码
import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    watchEffect(() => {
      console.log(`Result: ${base.value * multiplier.value}`);
    });

    return {
      base,
      multiplier
    };
  }
};

5. toRefs: 将对象的属性转换为响应式引用,以便直接在模板中使用。

javascript 复制代码
import { ref, toRefs } from 'vue';

export default {
  props: {
    user: {
      type: Object,
      required: true
    }
  },
  setup(props) {
    const { name, age } = toRefs(props.user);

    return {
      name,
      age
    };
  }
};

6. reactive: 创建一个响应式对象,允许深度监听对象的属性变化。

javascript 复制代码
import { reactive } from 'vue';

export default {
  setup() {
    const state = reactive({
      count: 0,
      user: {
        name: 'John Doe',
        age: 30
      }
    });

    function increment() {
      state.count++;
    }

    return {
      state,
      increment
    };
  }
};

7. provide/inject: 提供和注入依赖,类似于 Vue 2 中的非响应式版本,但Vue 3中可以提供响应式数据。

javascript 复制代码
// 父组件
import { provide } from 'vue';

export default {
  setup() {
    const theme = ref('light');

    provide('theme', theme);

    return {};
  }
};
javascript 复制代码
// 子组件
import { inject } from 'vue';

export default {
  setup() {
    const theme = inject('theme');

    return {
      theme
    };
  }
};

8. watch with options:

提供更细粒度的控制,如深度监听、异步处理和仅在初始值更改时触发。

javascript 复制代码
import { ref, watch } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    watch(
      [base, multiplier],
      ([newBase, newMultiplier], [oldBase, oldMultiplier]) => {
        if (newBase !== oldBase || newMultiplier !== oldMultiplier) {
          console.log(`Result: ${newBase * newMultiplier}`);
        }
      },
      {
        deep: true, // 深度监听
        immediate: true // 初始值更改时立即触发回调
      }
    );

    return {
      base,
      multiplier
    };
  }
};

9. effectScope: 用于在特定作用域内运行副作用,便于清理和管理。

javascript 复制代码
import { effectScope, ref } from 'vue';

export default {
  setup() {
    const scope = effectScope();
    const count = ref(0);

    const stopEffect = scope.run(() => {
      console.log('Effect running');
      scope.watch(count, () => {
        console.log(`Count is now: ${count.value}`);
      });
    });

    return {
      count,
      stopEffect
    };
  }
};
相关推荐
踩着两条虫24 分钟前
如何评价VTJ.PRO?
前端·架构·ai编程
Mh1 小时前
鼠标跟随倾斜动效
前端·css·vue.js
小码哥_常2 小时前
Kotlin类型魔法:Any、Unit、Nothing 深度探秘
前端
Web极客码3 小时前
深入了解WordPress网站访客意图
服务器·前端·wordpress
幺风4 小时前
Claude Code 源码分析 — Tool/MCP/Skill 可扩展工具系统
前端·javascript·ai编程
vjmap4 小时前
唯杰地图CAD图层加高性能特效扩展包发布
前端·gis
ZC跨境爬虫4 小时前
3D 地球卫星轨道可视化平台开发 Day7(AI异步加速+卫星系列精简+AI Agent自动评论)
前端·人工智能·3d·html·json
ID_180079054734 小时前
淘宝 API 上货 / 商品搬家 业务场景实现 + JSON 返回示例
前端·javascript·json
M ? A4 小时前
Vue 动态组件在 React 中,VuReact 会如何实现?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
vipbic5 小时前
独立开发复盘:我用 Uni-app + Strapi v5 肝了一个“会上瘾”的打卡小程序
前端·微信小程序