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
用于创建响应式数据,increment
和 decrement
方法分别用于增加和减少计数器的值。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 并将返回的对象解构赋值给局部变量。这些变量可以直接在模板中使用,因为它们都是响应式的。
这种模式的好处在于:
- 逻辑分离:Hook 可以封装特定的业务逻辑,使得组件代码更清晰,更容易维护。
- 复用性:Hook 可以在多个组件之间共享,减少代码重复。
- 类型安全:在 TypeScript 中,自定义 Hook 可以提供类型定义,提高代码的可读性和可预测性。
- 响应式系统:通过 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
};
}
};