useStore #
简介 #
在 Vue 3 的组合式 API 中,Vuex 提供了 useStore 函数来获取 store 实例。
基本用法 #
获取 Store #
vue
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
return {
store
}
}
}
</script>
访问 State #
vue
<template>
<div>
<p>User: {{ user.name }}</p>
<p>Count: {{ count }}</p>
</div>
</template>
<script>
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
return {
user: computed(() => store.state.user),
count: computed(() => store.state.count)
}
}
}
</script>
访问 Getter #
vue
<template>
<div>
<p>Double Count: {{ doubleCount }}</p>
<p>Is Logged In: {{ isLoggedIn }}</p>
</div>
</template>
<script>
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
return {
doubleCount: computed(() => store.getters.doubleCount),
isLoggedIn: computed(() => store.getters['user/isLoggedIn'])
}
}
}
</script>
提交 Mutation #
vue
<template>
<button @click="increment">Increment</button>
<button @click="setCount(10)">Set Count to 10</button>
</template>
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
const increment = () => {
store.commit('INCREMENT')
}
const setCount = (value) => {
store.commit('SET_COUNT', value)
}
return {
increment,
setCount
}
}
}
</script>
分发 Action #
vue
<template>
<button @click="fetchUser">Load User</button>
<button @click="login">Login</button>
</template>
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
const fetchUser = async () => {
await store.dispatch('user/fetchProfile')
}
const login = async () => {
try {
await store.dispatch('user/login', {
username: 'john',
password: 'secret'
})
} catch (error) {
console.error(error)
}
}
return {
fetchUser,
login
}
}
}
</script>
封装组合式函数 #
基础封装 #
javascript
// composables/useUser.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useUser() {
const store = useStore()
const user = computed(() => store.state.user.profile)
const isLoggedIn = computed(() => store.getters['user/isLoggedIn'])
const userName = computed(() => store.getters['user/userName'])
const login = async (credentials) => {
return await store.dispatch('user/login', credentials)
}
const logout = () => {
store.commit('user/CLEAR_USER')
}
return {
user,
isLoggedIn,
userName,
login,
logout
}
}
使用封装 #
vue
<template>
<div>
<p v-if="isLoggedIn">Welcome, {{ userName }}</p>
<button v-else @click="handleLogin">Login</button>
<button v-if="isLoggedIn" @click="logout">Logout</button>
</div>
</template>
<script>
import { useUser } from '@/composables/useUser'
export default {
setup() {
const { user, isLoggedIn, userName, login, logout } = useUser()
const handleLogin = async () => {
await login({ username: 'john', password: 'secret' })
}
return {
user,
isLoggedIn,
userName,
logout,
handleLogin
}
}
}
</script>
模块封装 #
用户模块 #
javascript
// composables/useUserStore.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useUserStore() {
const store = useStore()
// State
const profile = computed(() => store.state.user.profile)
const token = computed(() => store.state.user.token)
const loading = computed(() => store.state.user.loading)
const error = computed(() => store.state.user.error)
// Getters
const isLoggedIn = computed(() => store.getters['user/isLoggedIn'])
const userName = computed(() => store.getters['user/userName'])
// Actions
const login = (credentials) => store.dispatch('user/login', credentials)
const logout = () => store.dispatch('user/logout')
const fetchProfile = () => store.dispatch('user/fetchProfile')
const updateProfile = (data) => store.dispatch('user/updateProfile', data)
return {
// State
profile,
token,
loading,
error,
// Getters
isLoggedIn,
userName,
// Actions
login,
logout,
fetchProfile,
updateProfile
}
}
购物车模块 #
javascript
// composables/useCartStore.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useCartStore() {
const store = useStore()
// State
const items = computed(() => store.state.cart.items)
const loading = computed(() => store.state.cart.loading)
// Getters
const itemCount = computed(() => store.getters['cart/itemCount'])
const total = computed(() => store.getters['cart/total'])
const isEmpty = computed(() => store.getters['cart/isEmpty'])
// Mutations
const addItem = (item) => store.commit('cart/ADD_ITEM', item)
const removeItem = (productId) => store.commit('cart/REMOVE_ITEM', productId)
const clearCart = () => store.commit('cart/CLEAR_CART')
// Actions
const fetchCart = () => store.dispatch('cart/fetchCart')
const checkout = () => store.dispatch('cart/checkout')
return {
// State
items,
loading,
// Getters
itemCount,
total,
isEmpty,
// Mutations
addItem,
removeItem,
clearCart,
// Actions
fetchCart,
checkout
}
}
TypeScript 支持 #
类型定义 #
typescript
// types/store.ts
import { Store } from 'vuex'
interface User {
id: number
name: string
email: string
}
interface RootState {
user: {
profile: User | null
token: string | null
}
cart: {
items: CartItem[]
}
}
// 扩展 ComponentCustomProperties
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$store: Store<RootState>
}
}
类型安全的组合式函数 #
typescript
// composables/useUserStore.ts
import { computed, ComputedRef } from 'vue'
import { useStore } from 'vuex'
import { User, RootState } from '@/types/store'
interface UseUserStore {
profile: ComputedRef<User | null>
isLoggedIn: ComputedRef<boolean>
login: (credentials: { username: string; password: string }) => Promise<User>
logout: () => void
}
export function useUserStore(): UseUserStore {
const store = useStore<RootState>()
return {
profile: computed(() => store.state.user.profile),
isLoggedIn: computed(() => !!store.state.user.token),
login: async (credentials) => {
return await store.dispatch('user/login', credentials)
},
logout: () => {
store.commit('user/CLEAR_USER')
}
}
}
实战示例 #
完整的用户认证 #
vue
<template>
<div>
<!-- 未登录 -->
<div v-if="!isLoggedIn">
<form @submit.prevent="handleLogin">
<input v-model="form.username" placeholder="Username" />
<input v-model="form.password" type="password" placeholder="Password" />
<button type="submit" :disabled="loading">
{{ loading ? 'Logging in...' : 'Login' }}
</button>
</form>
<p v-if="error" class="error">{{ error }}</p>
</div>
<!-- 已登录 -->
<div v-else>
<p>Welcome, {{ userName }}!</p>
<button @click="logout">Logout</button>
</div>
</div>
</template>
<script>
import { reactive } from 'vue'
import { useUserStore } from '@/composables/useUserStore'
export default {
setup() {
const {
isLoggedIn,
userName,
loading,
error,
login,
logout
} = useUserStore()
const form = reactive({
username: '',
password: ''
})
const handleLogin = async () => {
try {
await login(form)
form.username = ''
form.password = ''
} catch (e) {
// Error is handled in store
}
}
return {
form,
isLoggedIn,
userName,
loading,
error,
handleLogin,
logout
}
}
}
</script>
最佳实践 #
1. 封装可复用的组合式函数 #
javascript
// 推荐:封装成组合式函数
export function useUser() {
const store = useStore()
// ...
}
// 不推荐:每个组件重复写
setup() {
const store = useStore()
const user = computed(() => store.state.user)
// ...
}
2. 使用 computed 保持响应式 #
javascript
// 推荐:使用 computed
const user = computed(() => store.state.user)
// 不推荐:直接返回值
const user = store.state.user // 不会更新
3. 模块化组织 #
javascript
// composables/
// ├── useUserStore.js
// ├── useCartStore.js
// └── useProductStore.js
总结 #
useStore 使用要点:
| 操作 | 方法 |
|---|---|
| 获取 store | useStore() |
| 访问 state | computed(() => store.state.xxx) |
| 访问 getter | computed(() => store.getters.xxx) |
| 提交 mutation | store.commit('XXX') |
| 分发 action | store.dispatch('xxx') |
继续学习 组合式函数封装,深入了解状态逻辑封装。
最后更新:2026-03-28