0Pricing
Frontend Academy · 课时

可组合函数:可复用的组合式函数

将响应式逻辑提取到以 use 开头的可组合函数中,在组件之间共享,并了解它们与混入的区别。

可组合函数:可复用的组合式函数 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

什么是组合式函数?

组合式函数是使用组合式 API 钩子来封装和复用有状态逻辑的函数。它们相当于组合式 API 版本的混入,但没有命名空间冲突或隐藏依赖。

基本组合式函数

将响应式逻辑提取到一个以 use 开头的函数中。它可以像 setup() 一样使用 ref、computed、watch 和生命周期钩子。

// useCounter.ts
import { ref } from 'vue';

export function useCounter(initial = 0) {
  const count = ref(initial);
  const increment = () => count.value++;
  const decrement = () => count.value--;
  const reset = () => (count.value = initial);
  return { count, increment, decrement, reset };
}

// Usage in any component:
const { count, increment } = useCounter(10);

带生命周期钩子的组合式函数

组合式函数可以注册生命周期钩子。钩子会相对于调用该组合式函数的组件触发。

// useOnlineStatus.ts
import { ref, onMounted, onUnmounted } from 'vue';

export function useOnlineStatus() {
  const isOnline = ref(navigator.onLine);

  const update = () => (isOnline.value = navigator.onLine);

  onMounted(() => {
    window.addEventListener('online', update);
    window.addEventListener('offline', update);
  });
  onUnmounted(() => {
    window.removeEventListener('online', update);
    window.removeEventListener('offline', update);
  });

  return { isOnline };
}

带异步操作的组合式函数(useFetch)

组合式函数非常适合异步数据获取——可以封装加载、错误和数据这一常见模式。

// useFetch.ts
export function useFetch<T>(url: MaybeRef<string>) {
  const data = ref<T | null>(null);
  const loading = ref(true);
  const error = ref<string | null>(null);

  watchEffect(async (onCleanup) => {
    const controller = new AbortController();
    onCleanup(() => controller.abort());
    loading.value = true;
    error.value = null;
    try {
      const res = await fetch(unref(url), { signal: controller.signal });
      data.value = await res.json();
    } catch (e: any) {
      if (e.name !== 'AbortError') error.value = e.message;
    } finally { loading.value = false; }
  });

  return { data, loading, error };
}

接受 ref 作为参数

组合式函数可以使用 MaybeRef<T>(= T | Ref<T>)和 unref() 作为参数,从而接受普通值或 ref。

import type { MaybeRef } from 'vue';
import { unref } from 'vue';

function useDouble(num: MaybeRef<number>) {
  return computed(() => unref(num) * 2);
}

组合式函数与混入

混入会在没有明确来源的情况下向组件注入属性。组合式函数则明确清晰——您可以从其返回值准确看出它提供了什么。可以同时使用多个组合式函数,而不会产生命名冲突。

在组件之间共享状态

如果组合式函数在自身内部调用 ref(),每个调用它的组件都会获得自己的状态。要在组件之间共享状态,请在模块作用域中调用 ref()(位于组合式函数外部)。

// Shared state (module-level):
const sharedCount = ref(0);

export function useSharedCounter() {
  // All callers share the same sharedCount
  return { count: sharedCount, increment: () => sharedCount.value++ };
}

组合式函数库

VueUse(vueuse.org)提供 200 多个可直接使用的组合式函数:useLocalStorage、useFetch、useDark、useIntersectionObserver 等。编写新代码前,请先查看 VueUse。

测试组合式函数

可以在小型测试组件中调用组合式函数来测试它们,也可以使用 @vue/test-utils 的 mountedApp 模式。Vitest 与 Vue 的响应式系统集成良好。

组合式函数命名约定

始终使用 use 作为前缀(useAuth、useFetch、useMediaQuery)。让每个组合式函数专注于单一职责。避免编写包含过多无关功能的组合式函数。

组合式函数的组织方式

创建一个 composables/ 文件夹。每个组合式函数使用一个文件。索引文件重新导出所有组合式函数。这与 React 项目中组织自定义钩子的方式相似。

快速检查

组合式函数相比 Vue 混入的主要优势是什么?

总结:Vue 组合式函数

组合式函数是以 use 为前缀、调用组合式 API 钩子的函数。除非使用模块级 ref,否则每个调用者都会获得独立的状态。使用 MaybeRef + unref 接受 ref 或普通值。在组合式函数内部注册生命周期钩子。编写自己的组合式函数前先查看 VueUse。明确的返回值可以避免混入式的命名空间污染。

常见问题解答

「可组合函数:可复用的组合式函数」课时是免费的吗?

是的 — 「可组合函数:可复用的组合式函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。

「可组合函数:可复用的组合式函数」这节课中我会学到什么?

将响应式逻辑提取到以 use 开头的可组合函数中,在组件之间共享,并了解它们与混入的区别。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Frontend Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「可组合函数:可复用的组合式函数」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Frontend Academy 课中编写并运行代码吗?

能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. ref() 与 reactive()
  2. computed() 与 watch()
  3. setup() 函数与 script setup
  4. 可组合函数:可复用的组合式函数
← 返回 Frontend Academy