前言
随着前端框架的不断演进,Vue.js 也在不断地适应和改进,以提供更优雅和高效的开发体验。在 Vue 3 中,Composition API 的引入给开发者带来了很多新颖的编程方式。
今天,我们来探讨一下 Vue Composition API 的主要特性以及它们所带来的优势。
什么是 Composition API?
在 Vue 2 中,我们主要使用 Options API 来定义组件的逻辑和状态。然而,随着项目规模的扩大,组件逻辑可能会变得复杂且难以维护。Composition API 提供了一种更灵活和可组合的方式来组织代码,使得代码更加清晰和模块化。
常用 API 列表
1. setup
setup 函数是 Composition API 的核心。它是一个新的组件选项,用于定义组件的逻辑和状态。
import { ref } from 'vue';export default {setup() {const count = ref(0);const increment = () => {count.value++;};return { count, increment };},
};
2. ref 和 reactive
ref 和 reactive 是 Composition API 中最常用的两个函数,用于创建响应式变量和对象。
- ref:用于基本数据类型(如数字、字符串、布尔值等)的响应式状态。
import { ref } from 'vue';const count = ref(0);
count.value++; // 通过 .value 访问和修改值
- reactive:用于复杂数据类型(如对象和数组)的响应式状态。
import { reactive } from 'vue';const state = reactive({count: 0,user: {name: 'Alice',age: 30}
});state.count++;
state.user.age++;
3. computed
computed 用于创建响应式计算属性,它会根据依赖的数据自动更新。
import { ref, computed } from 'vue';const count = ref(0);
const doubleCount = computed(() => count.value * 2);count.value = 2; // doubleCount 的值会自动更新为 4
4. watch 和 watchEffect
watch 和 watchEffect 用于监听响应式数据的变化。
- watch:用于监听特定的响应式数据,并执行副作用。
import { ref, watch } from 'vue';const count = ref(0);
watch(count, (newValue, oldValue) => {console.log(`count changed from ${oldValue} to ${newValue}`);
});
- watchEffect:用于立即执行并响应所有依赖的变化,适合处理复杂的副作用逻辑。
import { ref, watchEffect } from 'vue';const count = ref(0);
watchEffect(() => {console.log(`count is now ${count.value}`);
});
5. 生命周期钩子
Vue Composition API 通过一系列 onXXX 函数提供了生命周期钩子。
- onMounted:组件挂载时调用
- onUnmounted:组件卸载时调用
- onUpdated:组件更新时调用
- onBeforeMount:组件挂载前调用
- onBeforeUnmount:组件卸载前调用
- onBeforeUpdate:组件更新前调用
import { onMounted, onUnmounted } from 'vue';export default {setup() {onMounted(() => {console.log('Component is mounted');});onUnmounted(() => {console.log('Component is unmounted');});},
};
6. toRefs
当你使用 reactive 创建了一个响应式对象时,可能需要将对象内的属性拆解为单独的引用。toRefs 就是为此而生的。
import { reactive, toRefs } from 'vue';export default {setup() {const state = reactive({count: 0,name: 'Vue'});// 将 state 的属性解构为单独的 refconst { count, name } = toRefs(state);return { count, name };},
};
7. toRef
与 toRefs 类似,但 toRef 只将对象中的单个属性转换为引用。
import { reactive, toRef } from 'vue';export default {setup() {const state = reactive({count: 0,name: 'Vue'});const count = toRef(state, 'count');return { count };},
};
8. provide 和 inject
Composition API 提供了 provide 和 inject,用于在组件树中进行依赖注入,允许父组件向子组件传递数据或方法,而无需通过 props 层层传递。
// 父组件
import { provide } from 'vue';export default {setup() {const theme = 'dark';provide('theme', theme);},template: '<Child />',
};// 子组件
import { inject } from 'vue';export default {setup() {const theme = inject('theme');return { theme };},template: '<div>{{ theme }}</div>',
};
9. customRef
customRef 允许你自定义一个响应式引用,这在需要精细控制响应式行为时非常有用。
import { customRef } from 'vue';function useDebouncedRef(value, delay = 200) {let timeout;return customRef((track, trigger) => ({get() {track();return value;},set(newValue) {clearTimeout(timeout);timeout = setTimeout(() => {value = newValue;trigger();}, delay);},}));
}export default {setup() {const debouncedValue = useDebouncedRef('initial value');return { debouncedValue };},
};
10. markRaw 和 shallowRef
这些 API 用于创建非响应式或浅响应式的数据。
- markRaw:标记一个对象,使其不被 Vue 转换为响应式对象。
import { markRaw } from 'vue';const rawData = markRaw({foo: 'bar'
});
- shallowRef:创建一个浅响应式引用,仅对其值的顶层属性进行响应式处理。
import { shallowRef } from 'vue';const state = shallowRef({nested: {value: 123}
});state.value = { newProp: 'new' }; // 响应式
state.value.nested.value = 456; // 非响应式11. shallowReactive
与 shallowRef 类似,但用于创建浅响应式对象。
import { shallowReactive } from 'vue';const state = shallowReactive({nested: {value: 123}
});state.nested.value = 456; // 非响应式
12. readonly
创建一个只读的响应式对象,防止其被修改。
import { reactive, readonly } from 'vue';const state = reactive({count: 0
});const readonlyState = readonly(state);readonlyState.count = 1; // 无效操作,readonlyState 是只读的
Composition API 的优势
1. 代码可重用性
Composition API 允许我们将逻辑提取到独立的函数中,这些函数可以在不同的组件中复用。这种方式大大提高了代码的可重用性和可维护性。
// hooks/useCounter.js
import { ref } from 'vue';export function useCounter() {const count = ref(0);const increment = () => {count.value++;};return { count, increment };
}// 组件中使用
import { useCounter } from './hooks/useCounter';export default {setup() {const { count, increment } = useCounter();return { count, increment };},
};
2. 更好的逻辑组织
通过 Composition API,我们可以将相关的逻辑聚合在一起,而不是分散在组件的生命周期钩子和选项中。这使得代码更具组织性和可读性。
3. 更容易的类型推断
由于 Composition API 主要使用函数和标准的 JavaScript 语法,TypeScript 可以更好地推断出类型,提高了类型安全性和代码的可靠性。
4. 支持更强的逻辑组合
在开发复杂应用时,我们通常会有一些跨组件的逻辑,而 Composition API 允许我们更方便地组合这些逻辑,使得开发复杂的功能变得更加简单和直观。
实际应用场景
1. 表单处理
在表单处理方面,Composition API 可以让我们更清晰地组织表单的验证逻辑和数据管理。
import { ref } from 'vue';export default {setup() {const username = ref('');const password = ref('');const login = () => {if (!username.value || !password.value) {alert('Please enter username and password');return;}// 处理登录逻辑};return { username, password, login };},
};
2. 使用自定义 Hook
自定义 Hook 可以帮助我们将逻辑抽象出来,变得更可重用。
// hooks/useFetch.js
import { ref, onMounted } from 'vue';export function useFetch(url) {const data = ref(null);const error = ref(null);const fetchData = async () => {try {const response = await fetch(url);data.value = await response.json();} catch (err) {error.value = err;}};onMounted(fetchData);return { data, error, fetchData };
}// 组件中使用
import { useFetch } from './hooks/useFetch';export default {setup() {const { data, error, fetchData } = useFetch('https://api.example.com/data');return { data, error, fetchData };},
};
3. 动态主题切换
我们可以利用 reactive 和 watch 实现动态主题切换。
import { reactive, watch } from 'vue';export default {setup() {const theme = reactive({color: 'light'});watch(() => theme.color,(newColor) => {document.body.className = newColor;});const toggleTheme = () => {theme.color = theme.color === 'light' ? 'dark' : 'light';};return { theme, toggleTheme };},
};
总结
Vue Composition API 为我们提供了一种更灵活和模块化的方式来编写 Vue 组件。它不仅增强了代码的可重用性和可维护性,还使得复杂逻辑的组织变得更加清晰。通过了解和掌握 Composition API,我们可以更高效地开发和维护 Vue 应用。