Vuex与Composition API整合实践指南
Vuex 与 Composition API 的深度整合实践
一、useStore 组合式函数
在 Vue 3 的 Composition API 中,我们可以通过 useStore
函数来访问 Vuex store 实例。这是 Vuex 4 为 Composition API 提供的内置支持。
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
// 现在可以通过 store 访问所有 Vuex 功能
return {
store
}
}
}
实践建议:
- 在大型应用中,建议在
setup()
顶部统一获取 store 实例 - 可以将
useStore()
的结果赋给一个具有语义化的变量名,如userStore
或productStore
二、在 setup 中访问 State 和 Getters
访问 State
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
// 直接访问 state
const count = computed(() => store.state.count)
// 使用展开运算符访问多个 state
const { username, userId } = computed(() => ({
username: store.state.user.name,
userId: store.state.user.id
})).value
return {
count,
username,
userId
}
}
}
访问 Getters
setup() {
const store = useStore()
// 访问 getter
const doubleCount = computed(() => store.getters.doubleCount)
// 带参数的 getter
const getUserById = (id) => computed(() => store.getters.getUserById(id))
return {
doubleCount,
getUserById
}
}
实践建议:
- 始终使用
computed
包装 state 和 getters,确保响应性 - 对于频繁访问的 state,考虑使用解构赋值提高代码可读性
- 对于带参数的 getters,可以封装成函数形式返回计算属性
三、封装自定义 Vuex 组合逻辑
我们可以将常用的 Vuex 操作封装成可复用的组合式函数,这是 Composition API 的最大优势之一。
基础封装示例
// useUserStore.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useUserStore() {
const store = useStore()
const currentUser = computed(() => store.state.user.current)
const isLoggedIn = computed(() => store.getters['user/isLoggedIn'])
const login = (credentials) => store.dispatch('user/login', credentials)
const logout = () => store.dispatch('user/logout')
return {
currentUser,
isLoggedIn,
login,
logout
}
}
带命名空间的模块封装
// useProductStore.js
export function useProductStore() {
const store = useStore()
// 使用命名空间路径访问模块
const products = computed(() => store.state.products.items)
const featuredProducts = computed(() => store.getters['products/featured'])
const fetchProducts = () => store.dispatch('products/fetchAll')
const addProduct = (product) => store.dispatch('products/add', product)
return {
products,
featuredProducts,
fetchProducts,
addProduct
}
}
高级封装:带选项的组合函数
// usePaginatedData.js
export function usePaginatedData(moduleName, options = {}) {
const { pageSize = 10 } = options
const store = useStore()
const items = computed(() => store.state[moduleName].items)
const currentPage = computed(() => store.state[moduleName].pagination.page)
const paginatedItems = computed(() => {
const start = (currentPage.value - 1) * pageSize
return items.value.slice(start, start + pageSize)
})
const setPage = (page) => store.commit(`${moduleName}/SET_PAGE`, page)
return {
items,
currentPage,
paginatedItems,
setPage
}
}
实践建议:
- 按照业务领域而非技术功能组织组合函数
- 为复杂的组合函数添加 JSDoc 注释说明用法
- 考虑将组合函数放在单独的
composables
目录中 - 对于跨多个组件的通用逻辑,优先使用组合函数而非 mixins
四、响应式操作的最佳实践
import { watch, toRefs } from 'vue'
export function useCart() {
const store = useStore()
const cartItems = computed(() => store.state.cart.items)
const cartTotal = computed(() => store.getters['cart/total'])
// 使用 toRefs 确保解构后保持响应性
const { items, checkoutStatus } = toRefs(store.state.cart)
// 监听 cartItems 变化
watch(cartItems, (newItems) => {
if (newItems.length > 5) {
console.warn('Cart has more than 5 items')
}
}, { deep: true })
const checkout = async () => {
try {
await store.dispatch('cart/checkout')
// 处理成功逻辑
} catch (error) {
// 处理错误
}
}
return {
cartItems,
cartTotal,
checkout,
items,
checkoutStatus
}
}
五、与 TypeScript 的类型集成
import { computed } from 'vue'
import { useStore } from 'vuex'
import { RootState } from '../store/types'
interface User {
id: number
name: string
email: string
}
export function useUserStore() {
const store = useStore<RootState>()
const currentUser = computed<User | null>(() => store.state.user.current)
const isAdmin = computed<boolean>(() => store.getters['user/isAdmin'])
const updateProfile = (payload: { name: string; email: string }) => {
return store.dispatch('user/updateProfile', payload)
}
return {
currentUser,
isAdmin,
updateProfile
}
}
架构建议:
- 对于中小型应用,可以直接在组件中使用
useStore
- 对于大型应用,推荐为每个业务模块创建专用的组合函数
- 组合函数应该聚焦单一职责,避免成为"上帝对象"
考虑将组合函数分为:
- 只读操作(state/getters)
- 写入操作(mutations/actions)
- 复杂业务逻辑
通过这种模式,我们可以在 Vue 3 应用中实现:
- 更好的类型推断(配合 TypeScript)
- 更清晰的逻辑组织
- 更高的代码复用性
- 更简单的单元测试
总结
Vuex 与 Composition API 的结合为状态管理带来了新的可能性。通过 useStore
和自定义组合函数,我们可以创建更具表达力和可维护性的状态逻辑。关键是要找到适合项目规模的抽象层级 - 小型项目可能只需要基本的 useStore
使用,而大型应用则能从精心设计的组合函数中获益良多。
评论已关闭