Vue 3.4 Composition API最佳实践:从基础到高级技巧
Vue 3的Composition API彻底改变了Vue应用的开发方式,提供了更灵活、更强大的代码组织能力。随着Vue 3.4的发布,Composition API变得更加成熟和完善。本文将深入探讨Composition API的最佳实践,涵盖从基础使用到高级技巧的各个方面。
1. 基础模式:正确的响应式数据管理
正确使用响应式API是Composition API的基础。理解不同API的适用场景至关重要。
import { ref, reactive, computed, watch, watchEffect } from "vue";
// 1. ref - 适用于基本类型和对象引用
const count = ref(0);
const user = ref({ name: "Alice", age: 25 });
// 2. reactive - 适用于复杂对象
const state = reactive({
items: [],
loading: false,
error: null
});
// 3. computed - 计算属性
const totalItems = computed(() => state.items.length);
const filteredItems = computed(() => {
return state.items.filter(item => item.active);
});
// 4. watch - 精确监听
watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`);
}, { immediate: true });
// 5. watchEffect - 自动依赖追踪
watchEffect(() => {
console.log(`Total items: ${totalItems.value}`);
if (totalItems.value > 10) {
console.log("Too many items!");
}
});
// 最佳实践:统一响应式数据源
const useUserStore = () => {
const user = ref(null);
const isAuthenticated = computed(() => !!user.value);
const login = async (credentials) => {
try {
const response = await api.login(credentials);
user.value = response.data;
localStorage.setItem("token", response.token);
} catch (error) {
console.error("Login failed:", error);
throw error;
}
};
const logout = () => {
user.value = null;
localStorage.removeItem("token");
};
return {
user: readonly(user),
isAuthenticated,
login,
logout
};
};
2. 组合式函数:可复用的逻辑封装
组合式函数是Composition API的核心,让逻辑复用变得简单直观。
// useFetch - 通用的数据获取hook
import { ref, watchEffect } from "vue";
export function useFetch(url, options = {}) {
const data = ref(null);
const error = ref(null);
const loading = ref(false);
const fetchData = async () => {
loading.value = true;
error.value = null;
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
data.value = await response.json();
} catch (err) {
error.value = err;
data.value = null;
} finally {
loading.value = false;
}
};
// 自动重新获取(当url变化时)
watchEffect(() => {
if (url) {
fetchData();
}
});
return {
data,
error,
loading,
refresh: fetchData
};
}
// useLocalStorage - 本地存储hook
import { ref, watch } from "vue";
export function useLocalStorage(key, defaultValue) {
const data = ref(defaultValue);
// 从localStorage读取初始值
try {
const item = localStorage.getItem(key);
if (item) {
data.value = JSON.parse(item);
}
} catch (error) {
console.error(`Error reading localStorage key "${key}":`, error);
}
// 监听变化并保存到localStorage
watch(data, (newValue) => {
try {
localStorage.setItem(key, JSON.stringify(newValue));
} catch (error) {
console.error(`Error saving to localStorage key "${key}":`, error);
}
}, { deep: true });
return data;
}
// useDebounce - 防抖hook
import { ref, watch } from "vue";
export function useDebounce(value, delay = 300) {
const debouncedValue = ref(value.value);
let timeoutId = null;
watch(value, (newValue) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
debouncedValue.value = newValue;
}, delay);
});
return debouncedValue;
}
// 在组件中使用
import { useFetch, useLocalStorage, useDebounce } from "./composables";
const Component = {
setup() {
const searchQuery = ref("");
const debouncedQuery = useDebounce(searchQuery, 500);
const { data: users, loading, error } = useFetch(
`https://api.example.com/users?q=${debouncedQuery.value}`
);
const theme = useLocalStorage("theme", "light");
return {
searchQuery,
users,
loading,
error,
theme
};
}
};
3. TypeScript集成:类型安全的Composition API
Vue 3.4对TypeScript的支持更加完善,充分利用类型系统可以大幅提升代码质量。
import { ref, computed, Ref, ComputedRef } from "vue";
// 定义类型
interface User {
id: number;
name: string;
email: string;
role: "admin" | "user" | "guest";
}
interface Pagination {
page: number;
limit: number;
total: number;
}
// 类型安全的组合式函数
function useUserManagement() {
const users: Ref = ref([]);
const selectedUser: Ref = ref(null);
const loading: Ref = ref(false);
const pagination: Ref = ref({
page: 1,
limit: 20,
total: 0
});
// 计算属性类型
const totalPages: ComputedRef = computed(() => {
return Math.ceil(pagination.value.total / pagination.value.limit);
});
const hasNextPage: ComputedRef = computed(() => {
return pagination.value.page < totalPages.value;
});
// 异步函数类型
async function fetchUsers(): Promise {
loading.value = true;
try {
const response = await api.getUsers({
page: pagination.value.page,
limit: pagination.value.limit
});
users.value = response.data;
pagination.value.total = response.total;
} catch (error) {
console.error("Failed to fetch users:", error);
throw error;
} finally {
loading.value = false;
}
}
function selectUser(user: User): void {
selectedUser.value = user;
}
function updateUser(id: number, updates: Partial): void {
const index = users.value.findIndex(user => user.id === id);
if (index !== -1) {
users.value[index] = { ...users.value[index], ...updates };
}
}
return {
users: users as Readonly>>,
selectedUser,
loading,
pagination,
totalPages,
hasNextPage,
fetchUsers,
selectUser,
updateUser
};
}
// 泛型组合式函数
function useResource(fetchFn: () => Promise) {
const data: Ref = ref(null);
const loading = ref(false);
const error = ref(null);
async function load() {
loading.value = true;
error.value = null;
try {
data.value = await fetchFn();
} catch (err) {
error.value = err as Error;
data.value = null;
} finally {
loading.value = false;
}
}
return {
data,
loading,
error,
load
};
}
// 使用示例
const { data: post, load: loadPost } = useResource(() =>
api.getPost(1)
);
4. 性能优化:避免常见的性能陷阱
Composition API虽然强大,但也需要注意性能优化。
// 1. 避免不必要的响应式
import { ref, shallowRef, markRaw } from "vue";
// 大型对象使用shallowRef
const largeData = shallowRef({ /* 大量数据 */ });
// 静态配置使用markRaw
const config = markRaw({
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
});
// 2. 合理使用watch和watchEffect
const searchQuery = ref("");
const selectedCategory = ref("all");
// 不好的做法:多个独立的watch
watch(searchQuery, fetchResults);
watch(selectedCategory, fetchResults);
// 好的做法:合并监听
watch([searchQuery, selectedCategory], ([query, category]) => {
fetchResults(query, category);
}, { immediate: true });
// 3. 使用computed缓存计算结果
const expensiveCalculation = computed(() => {
// 复杂的计算逻辑
return heavyData.value.reduce((sum, item) => {
return sum + processItem(item);
}, 0);
});
// 4. 懒加载组合式函数
const useHeavyFeature = () => {
// 只有在需要时才导入
const heavyModule = import("./heavy-module");
return {
// ...
};
};
// 5. 使用provide/inject进行状态共享
// 父组件
import { provide, reactive } from "vue";
const App = {
setup() {
const appState = reactive({
theme: "light",
language: "zh-CN",
user: null
});
provide("appState", appState);
return { appState };
}
};
// 子组件
import { inject } from "vue";
const ChildComponent = {
setup() {
const appState = inject("appState");
return { appState };
}
};
5. 测试组合式函数
组合式函数的可测试性是其重要优势之一。
// useCounter.js
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
const reset = () => {
count.value = initialValue;
};
return {
count: readonly(count),
increment,
decrement,
reset
};
}
// useCounter.test.js
import { describe, it, expect } from "vitest";
import { ref } from "vue";
import { useCounter } from "./useCounter";
describe("useCounter", () => {
it("should initialize with default value", () => {
const { count } = useCounter();
expect(count.value).toBe(0);
});
it("should initialize with custom value", () => {
const { count } = useCounter(10);
expect(count.value).toBe(10);
});
it("should increment the count", () => {
const { count, increment } = useCounter(5);
increment();
expect(count.value).toBe(6);
});
it("should decrement the count", () => {
const { count, decrement } = useCounter(5);
decrement();
expect(count.value).toBe(4);
});
it("should reset to initial value", () => {
const { count, increment, reset } = useCounter(5);
increment();
increment();
expect(count.value).toBe(7);
reset();
expect(count.value).toBe(5);
});
it("should not allow direct mutation", () => {
const { count } = useCounter(5);
// count.value = 10; // TypeScript会报错,JavaScript会静默失败
expect(count.value).toBe(5);
});
});
总结
Vue 3.4的Composition API为Vue应用开发带来了革命性的改进:
- 更好的代码组织:逻辑关注点分离,代码更易维护
- 更强的复用性:组合式函数让逻辑复用变得简单
- 更完善的TypeScript支持:类型安全大幅提升开发体验
- 更灵活的响应式系统:细粒度的响应式控制
- 更好的可测试性:组合式函数易于单元测试
掌握Composition API的最佳实践,可以帮助开发者构建更健壮、更可维护的Vue应用。建议从基础模式开始,逐步掌握高级技巧,并在实际项目中不断实践和优化。
随着Vue生态的不断发展,Composition API将继续演进,为开发者提供更强大的工具。保持学习的态度,关注官方文档和社区动态,是提升Vue开发技能的关键。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END




暂无评论内容