Vue 3 Composition API实战指南:从Options到Composition的平滑迁移

Composition API简介

Vue 3的Composition API是Vue生态系统中最重要的革新之一。它提供了一种更灵活、更强大的方式来组织和复用组件逻辑。与传统的Options API相比,Composition API让代码更具可读性、可维护性和可测试性。

Options API vs Composition API

Options API(传统方式)

// Options API示例
export default {
  data() {
    return {
      count: 0,
      message: "Hello Vue!"
    };
  },
  computed: {
    doubledCount() {
      return this.count * 2;
    }
  },
  methods: {
    increment() {
      this.count++;
    },
    reset() {
      this.count = 0;
    }
  },
  mounted() {
    console.log("组件已挂载");
  }
};

Composition API(新方式)

// Composition API示例
import { ref, computed, onMounted } from "vue";

export default {
  setup() {
    // 响应式数据
    const count = ref(0);
    const message = ref("Hello Vue!");
    
    // 计算属性
    const doubledCount = computed(() => count.value * 2);
    
    // 方法
    const increment = () => {
      count.value++;
    };
    
    const reset = () => {
      count.value = 0;
    };
    
    // 生命周期钩子
    onMounted(() => {
      console.log("组件已挂载");
    });
    
    // 返回模板可用的数据和方法
    return {
      count,
      message,
      doubledCount,
      increment,
      reset
    };
  }
};

核心响应式API详解

1. ref – 创建响应式引用

import { ref } from "vue";

// 创建响应式引用
const count = ref(0);
const user = ref({ name: "张三", age: 25 });

// 访问值
console.log(count.value); // 0
console.log(user.value.name); // "张三"

// 修改值
count.value = 10;
user.value.age = 26;

2. reactive – 创建响应式对象

import { reactive } from "vue";

// 创建响应式对象
const state = reactive({
  count: 0,
  user: {
    name: "李四",
    profile: {
      email: "lisi@example.com"
    }
  }
});

// 直接访问属性(无需.value)
console.log(state.count); // 0
console.log(state.user.profile.email); // "lisi@example.com"

// 修改属性
state.count = 5;
state.user.name = "王五";

3. computed – 计算属性

import { ref, computed } from "vue";

const price = ref(100);
const quantity = ref(2);

// 计算总价
const total = computed(() => price.value * quantity.value);

// 带getter和setter的计算属性
const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`;
  },
  set(newValue) {
    const [first, last] = newValue.split(" ");
    firstName.value = first;
    lastName.value = last;
  }
});

4. watch – 侦听器

import { ref, watch } from "vue";

const count = ref(0);
const user = ref({ name: "张三" });

// 侦听单个ref
watch(count, (newValue, oldValue) => {
  console.log(`count从${oldValue}变为${newValue}`);
});

// 侦听多个源
watch([count, user], ([newCount, newUser], [oldCount, oldUser]) => {
  console.log("count或user发生了变化");
});

// 深度侦听对象
watch(
  user,
  (newUser, oldUser) => {
    console.log("user对象发生变化");
  },
  { deep: true }
);

逻辑复用:Composable函数

创建可复用的逻辑

// useCounter.js - 计数器逻辑
import { ref, computed } from "vue";

export function useCounter(initialValue = 0) {
  const count = ref(initialValue);
  
  const increment = () => count.value++;
  const decrement = () => count.value--;
  const reset = () => count.value = initialValue;
  const double = computed(() => count.value * 2);
  
  return {
    count,
    increment,
    decrement,
    reset,
    double
  };
}

在组件中使用Composable

// Component.vue
import { useCounter } from "./useCounter";

export default {
  setup() {
    const { count, increment, reset, double } = useCounter(10);
    
    return {
      count,
      increment,
      reset,
      double
    };
  }
};

实际应用:用户管理组件

// useUserManagement.js
import { ref, computed, watch } from "vue";
import { fetchUserData, updateUserProfile } from "./api";

export function useUserManagement(userId) {
  const user = ref(null);
  const loading = ref(false);
  const error = ref(null);
  
  // 计算属性
  const isAdult = computed(() => {
    return user.value?.age >= 18;
  });
  
  const fullName = computed(() => {
    if (!user.value) return "";
    return `${user.value.firstName} ${user.value.lastName}`;
  });
  
  // 方法
  const loadUser = async () => {
    loading.value = true;
    error.value = null;
    
    try {
      user.value = await fetchUserData(userId);
    } catch (err) {
      error.value = err.message;
    } finally {
      loading.value = false;
    }
  };
  
  const updateUser = async (updates) => {
    try {
      await updateUserProfile(userId, updates);
      Object.assign(user.value, updates);
    } catch (err) {
      throw new Error(`更新失败: ${err.message}`);
    }
  };
  
  // 自动加载用户数据
  watch(() => userId, loadUser, { immediate: true });
  
  return {
    user,
    loading,
    error,
    isAdult,
    fullName,
    loadUser,
    updateUser
  };
}

TypeScript支持

// 使用TypeScript的Composition API
import { ref, computed, Ref } from "vue";

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

export function useUser() {
  // 类型化的ref
  const user: Ref = ref(null);
  const loading = ref(false);
  
  // 类型化的计算属性
  const userName = computed(() => {
    return user.value?.name || "未知用户";
  });
  
  const isAdult = computed(() => {
    return user.value?.age >= 18;
  });
  
  return {
    user,
    loading,
    userName,
    isAdult
  };
}

迁移策略

渐进式迁移

  1. 新组件使用Composition API:所有新开发的组件直接使用Composition API
  2. 复杂组件优先迁移:逻辑复杂的Options API组件优先迁移
  3. 提取可复用逻辑:将Options API中的逻辑提取为Composable函数
  4. 混合使用:在同一个项目中可以同时使用两种API

迁移工具

// 使用@vue/composition-api插件(Vue 2项目)
import Vue from "vue";
import VueCompositionAPI from "@vue/composition-api";

Vue.use(VueCompositionAPI);

// 在Vue 2组件中使用Composition API
export default {
  setup() {
    // Composition API代码
    const count = ref(0);
    return { count };
  }
};

最佳实践

  1. 合理组织setup函数:按功能模块组织代码,避免setup函数过于臃肿
  2. 使用Composable提取逻辑:将相关逻辑提取为可复用的Composable函数
  3. 类型安全:使用TypeScript获得更好的类型支持和代码提示
  4. 性能优化:合理使用computed和watch,避免不必要的重新计算
  5. 错误处理:在异步操作中添加适当的错误处理机制

总结

Composition API代表了Vue框架的未来发展方向。虽然学习曲线比Options API稍陡,但它带来的代码组织灵活性、逻辑复用能力和TypeScript支持是无可替代的。对于新项目,建议直接使用Composition API;对于现有项目,可以采用渐进式迁移策略。掌握Composition API将使您能够构建更健壮、更易维护的Vue应用。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容