章
目
录
在Vue开发中,组合式函数的作用可太大了,但要是使用不当,代码很容易变得杂乱无章,后期维护起来特别麻烦。今天这篇文章就给大家分享13个实用技巧,掌握了它们,能帮你编写出更优质、更易于维护的组合式函数代码。不管你是处理简单的状态管理,还是应对复杂的共享逻辑,这些技巧都能派上用场。下面咱们就详细来看看。
一、避免多层组件间传递props
在Vue组件开发里,组件之间传递数据是常有的事。但要是在好多层组件之间传来传去props和事件,代码会变得很混乱。这里有个数据存储模式可以解决这个问题。比如说,父子组件之间要是通过好多层prop drilling(也就是把数据从父组件层层传递到子组件)和事件冒泡来通信,就很麻烦。这时候,咱们可以创建一个共享的数据存储,任何组件都能把它导入进来使用。代码示例如下:
// 引入Vue的响应式工具和将响应式对象转换为普通对象的工具
import { reactive, toRefs } from 'vue'
// 创建一个响应式的状态对象,这里存放用户信息
const state = reactive({ user: { name: 'Alice' } })
// 导出一个函数,返回状态对象的普通对象形式,方便其他组件使用
export function useUserStore() {
return toRefs(state)
}
这个模式还有个好处,当兄弟组件或者关系没那么直接的“堂兄弟”组件需要共享相同数据的时候,也能轻松搞定,不用再在父组件里传来传去,也避免了状态重复的问题。
二、无关组件间共享数据
借助上面提到的数据存储模式,那些相互之间没直接关联的组件也能共享数据啦。举个例子,有两个兄弟组件都需要用到相同的用户对象,这时候就可以通过共享的组合式函数存储来实现。具体代码如下:
// SiblingA.vue文件中
import { useUserStore } from './useUserStore'
// 从共享的组合式函数中获取用户对象
const { user } = useUserStore()
// SiblingB.vue文件中
import { useUserStore } from './useUserStore'
const { user } = useUserStore()
这样,两个组件就能轻松共享数据,而不用再费其他周折了。
三、用清晰方法控制状态更新
数据存储模式除了方便共享数据,还提倡用清晰的方法来更新共享状态,而不是直接把整个响应式对象暴露出去。来看个例子:
// 引入Vue的响应式工具和创建只读属性的工具
import { reactive, readonly } from 'vue'
// 创建一个响应式的状态对象,这里表示暗黑模式的状态
const state = reactive({ darkMode: false })
// 定义一个函数,用于切换暗黑模式的状态
export function toggleDarkMode() {
state.darkMode = !state.darkMode
}
// 导出一个函数,返回暗黑模式的只读状态和切换函数
export function useUserStore() {
return {
darkMode: readonly(state.darkMode),
toggleDarkMode
}
}
这样,其他组件在使用的时候,既能获取到暗黑模式的状态,又能通过调用函数来切换状态,代码逻辑清晰又安全。
四、将大型组件拆分为小函数
有时候,组件代码量特别大,里面的refs和方法都混在一起,很难理清逻辑。这时候,内联组合式函数模式就能派上用场啦。它可以把相关的状态和逻辑组合到一个个小函数里,把大型组件拆分得更有条理。比如下面这段代码:
<script setup>
// 定义一个小函数,用于管理计数器的状态和操作
function useCounter() {
// 创建一个响应式的计数器变量,初始值为0
const count = ref(0)
// 定义一个函数,用于增加计数器的值
const increment = () => count.value++
// 返回计数器变量和增加函数
return { count, increment }
}
// 调用小函数,获取计数器变量和增加函数
const { count, increment } = useCounter()
</script>
之后,要是有需要,还能把这些小函数提取到单独的文件里,让代码结构更清晰。
五、将业务逻辑与Vue响应式分离
薄组合式函数模式建议把原始的业务逻辑和Vue的响应式功能分开处理。这样做的好处是,测试和维护代码都会变得更简单。比如说,把复杂的规则写在普通的纯函数里,组合式函数只负责处理响应式的包装。代码示例如下:
// counterLogic.js文件,存放业务逻辑
export function incrementCount(num) {
// 这里是业务逻辑,将传入的数字乘以3再除以2
return (num * 3) / 2
}
// useCounter.js文件,使用业务逻辑并处理响应式
import { ref } from 'vue'
import { incrementCount } from './counterLogic'
// 导出一个组合式函数,用于管理计数器
export function useCounter() {
// 创建一个响应式的计数器变量,初始值为0
const count = ref(0)
// 定义一个函数,用于增加计数器的值,调用了业务逻辑函数
function increment() {
count.value = incrementCount(count.value)
}
// 返回计数器变量和增加函数
return { count, increment }
}
通过这种方式,业务逻辑和响应式处理各司其职,代码的可读性和可维护性都大大提高了。
六、一个函数处理同步和异步数据
异步 + 同步组合式函数模式可以把同步和异步的行为都整合到一个组合式函数里。举个例子,有个组合式函数,它既可以返回一个Promise(用于异步操作),同时还能提供即时的响应式属性,方便同步使用。代码是这样的:
import { ref } from 'vue'
export function useAsyncOrSync() {
// 创建一个响应式变量,用于存储数据,初始值为null
const data = ref(null)
// 发起一个异步的fetch请求,获取数据
const promise = fetch('/api')
.then(res => res.json())
.then(json => {
// 将获取到的数据赋值给响应式变量
data.value = json
// 返回包含数据的对象
return { data }
})
// 将Promise和响应式数据对象合并后返回
return Object.assign(promise, { data })
}
这样,不管是同步还是异步的场景,都能通过这一个函数来满足需求,是不是很方便呢?
七、让函数参数更具描述性
当函数的参数比较多的时候,长长的参数列表看起来会很头疼,也容易出错。这时候,选项对象模式就能帮上忙啦。它通过让函数接收一个配置对象,来让函数调用变得更清晰、更具描述性。比如说:
useRefHistory(someRef, {
deep: true,
capacity: 10,
throttle: 500,
eventName: 'click',
immediate: false
})
从这段代码就能很清楚地看出每个参数的含义和作用,比一长串参数直观多了。
八、用默认值防止未定义选项
选项对象模式还有个很实用的点,就是可以为每个属性设置默认值。这样在使用的时候,就不用担心某个选项没传值而导致的问题了。来看个例子:
export function useRefHistory(someRef, {
deep = false,
capacity = Infinity,
...rest
} = {}) {
// 在这里,deep和capacity都有默认值,可以安全使用
}
在这个函数里,就算调用的时候没有给deep
和capacity
传值,它们也会有默认值,避免了因为未定义选项而引发的错误。
九、根据需要返回简单或复杂值
动态返回模式能让组合式函数根据实际需求,灵活地返回不同类型的值。有时候可能只需要返回一个简单的单个值,有时候则需要返回一个带有更多高级控制功能的扩展对象。比如下面这个例子:
export function useLocalStorage(key, defaultValue, { controls = false } = {}) {
// 创建一个响应式变量,用于存储本地存储的值,初始值为传入的默认值
const value = ref(defaultValue)
// 定义一个函数,用于删除本地存储的值,具体实现省略
function remove() { /* ... */ }
// 根据controls参数的值,决定返回单个值还是包含值和删除函数的对象
return controls? { value, remove } : value
}
这样一来,组合式函数的使用就更加灵活,能适应各种不同的业务场景。
十、将不同逻辑路径分离到各自函数
隐藏组合式函数模式提倡把那些互斥的逻辑分开处理,不要都写在同一个组合式函数里。比如说,一个应用有管理员和普通访客两种不同的操作逻辑,那就可以把它们分别写成不同的组合式函数:
export function useAdminFlow() {
// 这里只写管理员相关的逻辑
}
export function useGuestFlow() {
// 这里只写访客相关的逻辑
}
这样代码的逻辑就非常清晰,每个函数只负责自己的那部分功能,也方便后续的维护和扩展。
十一、一致处理响应式和原始值
灵活参数模式要求在组合式函数里,对输入和输出的数据进行统一处理,要么都当成响应式数据,要么都当成原始值,这样可以避免很多混淆的情况。比如说,我们可以用ref
把输入的数据统一转换为ref
:
import { ref, toValue } from 'vue'
export function useSomething(input) {
// 将输入的数据转换为响应式的ref,这样在函数里就统一处理为响应式数据了
const asRef = ref(input)
}
通过这种方式,能让代码在处理数据的时候更加规范和清晰。
十二、简化Ref解包
灵活参数模式还可以借助toValue
来简化ref
的解包过程。比如说下面这段代码:
import { toValue } from 'vue'
export function useLogger(msg) {
// 使用toValue将可能是ref的msg解包为原始值
const val = toValue(msg)
// 打印解包后的值
console.log(val)
}
这样,在处理可能是ref
的数据时,就不用再写很多复杂的解包代码了,让代码变得更加简洁。
十三、逐步从选项式API迁移到组合式API
对于一些之前用选项式API写的大型组件,可能一下子全部迁移到组合式API会比较困难。这时候,选项到组合模式就派上用场了,它可以让我们逐步进行迁移。比如说,把传统的选项式组件转换为script setup
的形式:
<script setup>
// 创建一个响应式的计数器变量,初始值为0
const count = ref(0)
// 创建一个计算属性,值为计数器的两倍
const double = computed(() => count.value * 2)
// 定义一个函数,用于增加计数器的值
function increment() {
count.value++
}
</script>
通过这种逐步迁移的方式,既能享受组合式API带来的好处,又不会因为改动太大而引入过多风险。
掌握了这13个Vue组合式函数技巧,相信大家在编写代码的时候会更加得心应手,代码的质量和可维护性也会大大提升。赶紧在自己的项目里试试吧!