Vuex

89 阅读2分钟

1. Vuex 的核心概念

Vuex 包含五个核心概念:

  • State:状态管理

  • Getters:计算属性

  • Mutations:同步修改状态

  • Actions:异步操作

  • Modules:模块化管理

2. 基础配置示例

// store/index.ts
import { createStore } from 'vuex'
import user from './modules/user'
import cart from './modules/cart'

export default createStore({
  state: {
    count: 0,
    todos: []
  },
  
  getters: {
    doneTodos: state => state.todos.filter(todo => todo.done),
    getTodoById: state => id => state.todos.find(todo => todo.id === id)
  },
  
  mutations: {
    INCREMENT(state, payload) {
      state.count += payload.amount
    },
    SET_TODOS(state, todos) {
      state.todos = todos
    }
  },
  
  actions: {
    async fetchTodos({ commit }) {
      const response = await api.getTodos()
      commit('SET_TODOS', response.data)
    },
    
    incrementAsync({ commit }, payload) {
      setTimeout(() => {
        commit('INCREMENT', payload)
      }, 1000)
    }
  },
  
  modules: {
    user,
    cart
  }
})

3. 模块化示例

// store/modules/user.ts
interface UserState {
  token: string | null;
  userInfo: any;
}

export default {
  namespaced: true,
  
  state: (): UserState => ({
    token: null,
    userInfo: null
  }),
  
  getters: {
    isLoggedIn: state => !!state.token,
    username: state => state.userInfo?.name
  },
  
  mutations: {
    SET_TOKEN(state, token: string) {
      state.token = token
    },
    SET_USER_INFO(state, info: any) {
      state.userInfo = info
    }
  },
  
  actions: {
    async login({ commit }, credentials) {
      try {
        const { token, user } = await api.login(credentials)
        commit('SET_TOKEN', token)
        commit('SET_USER_INFO', user)
        return true
      } catch (error) {
        return false
      }
    },
    
    async logout({ commit }) {
      await api.logout()
      commit('SET_TOKEN', null)
      commit('SET_USER_INFO', null)
    }
  }
}

4. 组件中使用 Vuex

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double Count: {{ doubleCount }}</p>
    <p>Username: {{ username }}</p>
    
    <button @click="increment">Increment</button>
    <button @click="incrementAsync">Async Increment</button>
    <button @click="logout">Logout</button>
    
    <ul>
      <li v-for="todo in doneTodos" :key="todo.id">
        {{ todo.text }}
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

// State
const count = computed(() => store.state.count)
const username = computed(() => store.getters['user/username'])

// Getters
const doubleCount = computed(() => store.getters.doubleCount)
const doneTodos = computed(() => store.getters.doneTodos)

// Mutations & Actions
const increment = () => {
  store.commit('INCREMENT', { amount: 1 })
}

const incrementAsync = () => {
  store.dispatch('incrementAsync', { amount: 1 })
}

const logout = () => {
  store.dispatch('user/logout')
}
</script>

5. 辅助函数使用

// 在 Options API 中使用
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
  computed: {
    // 映射 state
    ...mapState(['count']),
    ...mapState('user', ['userInfo']),
    
    // 映射 getters
    ...mapGetters(['doneTodos']),
    ...mapGetters('user', ['isLoggedIn'])
  },
  
  methods: {
    // 映射 mutations
    ...mapMutations(['INCREMENT']),
    ...mapMutations('user', ['SET_TOKEN']),
    
    // 映射 actions
    ...mapActions(['fetchTodos']),
    ...mapActions('user', ['login', 'logout'])
  }
}

6. 插件开发

// store/plugins/logger.ts
export default function createLogger() {
  return store => {
    store.subscribe((mutation, state) => {
      console.log('mutation type:', mutation.type)
      console.log('mutation payload:', mutation.payload)
      console.log('current state:', state)
    })
  }
}

// store/index.ts
import createLogger from './plugins/logger'

export default createStore({
  plugins: process.env.NODE_ENV !== 'production'
    ? [createLogger()]
    : []
})

7. TypeScript 支持

// store/types.ts
export interface RootState {
  count: number;
  todos: Todo[];
}

export interface Todo {
  id: number;
  text: string;
  done: boolean;
}

// store/index.ts
import { InjectionKey } from 'vue'
import { Store } from 'vuex'
import { RootState } from './types'

export const key: InjectionKey<Store<RootState>> = Symbol()

// main.ts
import { key } from './store'

app.use(store, key)

// 组件中使用
import { useStore } from 'vuex'
import { key } from '@/store'

const store = useStore(key)

要点:

1. Vuex 的使用场景:

  • 多个组件共享状态

  • 需要跨组件通信

  • 复杂的状态管理

  1. Vuex 的优点:
  • 集中式状态管理

  • 可预测的状态变更

  • 开发工具支持

  • 模块化管理

  1. Mutations vs Actions:
  • Mutations 必须是同步函数

  • Actions 可以包含异步操作

  • Actions 通过提交 Mutation 修改状态

  1. 性能优化:
  • 合理使用模块化

  • 避免不必要的状态更新

  • 使用 computed 缓存派生状态

  1. 调试技巧:
  • Vue DevTools

  • Vuex Logger 插件

  • 严格模式