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