Vuex 第三方库深度整合:Axios 与持久化实战指南

一、与 Axios 的深度整合

1.1 为什么需要整合 Axios

在 Vue 应用中,Vuex 负责状态管理,Axios 负责 HTTP 请求,两者结合可以实现前后端数据流的完整闭环。深度整合后可以实现:

  • 统一管理 API 请求状态
  • 自动触发 Vuex mutations/actions
  • 集中处理错误和加载状态

1.2 基础整合模式

最简单的整合方式是在 Vuex actions 中直接调用 Axios:

// store/modules/user.js
actions: {
  async fetchUser({ commit }, userId) {
    try {
      const response = await axios.get(`/api/users/${userId}`)
      commit('SET_USER', response.data)
    } catch (error) {
      commit('SET_ERROR', error.message)
    }
  }
}

1.3 高级封装方案

我们可以创建更优雅的封装:

// utils/api.js
export const createApiService = (axiosInstance, store) => {
  return {
    async get(url, config = {}, mutation) {
      try {
        const response = await axiosInstance.get(url, config)
        if (mutation) {
          store.commit(mutation, response.data)
        }
        return response
      } catch (error) {
        store.commit('SET_ERROR', error)
        throw error
      }
    },
    // 类似实现 post, put, delete 等方法
  }
}

// 在 store 初始化时
const api = createApiService(axios, store)

// 在 actions 中使用
actions: {
  async fetchPosts({ commit }) {
    await api.get('/posts', {}, 'SET_POSTS')
  }
}

1.4 请求状态管理最佳实践

图1

实践建议

  1. 为请求状态设计统一的 loading/error 状态结构
  2. 使用拦截器统一处理 token 和错误
  3. 考虑使用插件自动生成 API 相关的 Vuex 模块

二、持久化插件 (vuex-persistedstate) 的使用

2.1 为什么需要状态持久化

Vuex 默认是内存存储,页面刷新后状态会丢失。持久化可以:

  • 保持用户登录状态
  • 记住用户偏好设置
  • 实现离线应用的基础

2.2 vuex-persistedstate 基础使用

安装:

npm install vuex-persistedstate

基本配置:

import createPersistedState from 'vuex-persistedstate'

const store = new Vuex.Store({
  // ...
  plugins: [
    createPersistedState({
      key: 'my-vuex-store', // 存储的键名
      paths: ['user', 'settings'], // 只持久化这些模块
      storage: window.localStorage // 默认是 localStorage
    })
  ]
})

2.3 高级配置选项

createPersistedState({
  storage: {
    getItem: key => Cookies.get(key),
    setItem: (key, value) => Cookies.set(key, value, { expires: 7 }),
    removeItem: key => Cookies.remove(key)
  },
  reducer: (state) => {
    return {
      user: {
        token: state.user.token,
        rememberMe: state.user.rememberMe
      }
    }
  },
  filter: (mutation) => {
    // 只处理特定 mutation
    return mutation.type.startsWith('user/')
  }
})

2.4 安全注意事项

对于敏感数据:

createPersistedState({
  paths: ['user'],
  storage: {
    getItem: (key) => {
      const value = localStorage.getItem(key)
      return value ? decrypt(value) : null
    },
    setItem: (key, value) => {
      localStorage.setItem(key, encrypt(value))
    },
    removeItem: (key) => localStorage.removeItem(key)
  }
})

实践建议

  1. 不要持久化敏感信息(如密码)
  2. 考虑数据加密方案
  3. 设置合理的过期策略
  4. 对大型状态考虑使用 IndexedDB

三、综合实战案例

3.1 电商应用状态管理设计

图2

3.2 完整代码示例

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

const api = axios.create({
  baseURL: process.env.VUE_APP_API_URL,
  timeout: 10000
})

// 请求拦截器
api.interceptors.request.use(config => {
  const token = store.state.user.token
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// 响应拦截器
api.interceptors.response.use(
  response => response,
  error => {
    if (error.response.status === 401) {
      store.commit('user/LOGOUT')
    }
    return Promise.reject(error)
  }
)

const store = new Vuex.Store({
  modules: {
    user: {
      namespaced: true,
      state: () => ({
        token: null,
        profile: null
      }),
      mutations: {
        SET_TOKEN(state, token) {
          state.token = token
        },
        SET_PROFILE(state, profile) {
          state.profile = profile
        },
        LOGOUT(state) {
          state.token = null
          state.profile = null
        }
      },
      actions: {
        async login({ commit }, credentials) {
          const { data } = await api.post('/login', credentials)
          commit('SET_TOKEN', data.token)
          commit('SET_PROFILE', data.user)
        },
        async fetchProfile({ commit }) {
          const { data } = await api.get('/profile')
          commit('SET_PROFILE', data)
        }
      }
    },
    cart: {
      state: () => ({
        items: []
      }),
      // ... cart 相关 mutations 和 actions
    }
  },
  plugins: [
    createPersistedState({
      paths: ['user', 'cart'],
      storage: window.sessionStorage, // 使用 sessionStorage 而不是 localStorage
      reducer: (state) => ({
        user: {
          token: state.user.token // 只持久化 token
        },
        cart: state.cart
      })
    })
  ]
})

export default store

四、总结与最佳实践

4.1 Axios 整合要点

  • 使用拦截器统一处理认证和错误
  • 将 API 调用封装在 Vuex actions 中
  • 设计良好的请求状态管理结构

4.2 持久化实践建议

  • 按需持久化,不要存储整个状态树
  • 敏感数据考虑加密或避免持久化
  • 根据场景选择 localStorage、sessionStorage 或 Cookies

4.3 性能考量

  • 大型状态考虑使用 IndexedDB
  • 频繁更新的状态可能不适合持久化
  • 使用 reducer 函数控制存储内容

通过合理整合这些第三方库,可以构建出健壮、可维护的 Vuex 状态管理系统,为复杂应用提供坚实的基础架构。

评论已关闭