Skip to content

Vuex ​

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库,借鉴了 Flux、Redux 和 The Elm Architecture。

import { createStore, Store } from 'vuex';

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

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

const store = createStore({
  modules: {
    a: moduleA,
  }
})

export default store;
  • API接口
import { 
  version, 
  Store, 
  storeKey, 
  createStore, 
  useStore, 
  mapState, 
  mapMutations, 
  mapGetters, 
  mapActions, 
  createNamespacedHelpers, 
  createLogger 
} from 'vuex';

export default {
  setup () {
    const store = useStore()
  }
}
  • Store 实例属性
  • Store 实例方法

State与mapState辅助函数 ​

computed: {
  ...mapState([
    'app',
    'moduleA'
  ])
},

Getter与mapGetters辅助函数 ​

从 store 中的 state 中派生出一些状态。

getters: {
  doneTodos (state) {
    return state.todos.filter(todo => todo.done)
  }
}

computed: {
  ...mapGetters([
    'doneTodos'
  ])
}

// 通过属性访问
store.getters.doneTodos

Mutation与mapMutations辅助函数 ​

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

mutations: {
  increment (state, payload) {
    state.count++
  }
}

// 提交载荷(Payload)
store.commit('increment', {})
  • 订阅Mutation
const unsubscribe = store.subscribe((mutation, state) => {
  console.log(mutation.type)
  console.log(mutation.payload)
})

// 停止订阅
unsubscribe()

Action与mapActions辅助函数 ​

actions: {
  increment ({ commit }) {
    commit('increment')
  },
  async actionA ({ commit }, params) {
    commit('gotData', await getData())
  },
  async actionB ({ commit }, params) {
    return await getData();
  },
}

methods: {
  ...mapActions(['increment'])
}

// 派发
store.dispatch('increment', {})
store.dispatch('actionA').then(() => {
  // ...
})
  • 订阅Action
const unsubscribe = store.subscribeAction((action, state) => {
  console.log(action.type)
  console.log(action.payload)
})

// 停止订阅
unsubscribe()

按需加载 ​

Vuex状态管理,通过一次性注入业务逻辑,随着业务逻辑的增加,JS公共包体积就会膨胀变大,这严重影响了首次加载速度。

  • 示例一,在main.js添加
Vue.use(function() {
  Vue.mixin({
    beforeCreate: function() {
      // $options是组件选项,包含组件.vue文件的 `export default` 的属性
      // 为了拿到在组件定义的是否按需加载的属性值 `isNeedVuex`
      if(this.$options.isNeedVuex) {
        // 需要设置.vue文件的name属性,跟单文件组件名字命名一样
        let name = this.$options.name;
        import("./store/modules/" + name).then((res) => {
          console.log(res);
          // res.default就是代表我们在store/modules文件夹下对应文件的export default对象
          // registerModule是vuex自带的方法,请自行搜索
          // 第一个参数是动态注入的模块名,第二个参数是模块导出对象
          this.$store.registerModule(name, res.default);
        });
      }
    }
  });
});

组合式函数 ​

import { useStore } from 'vuex'

const store = useStore()

缓存页面数据 ​

//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload",()=>{
    sessionStorage.setItem("store", JSON.stringify(this.$store.state))
})

内置Logger插件 ​

Vuex 自带一个日志插件用于一般的调试。

import { createLogger } from 'vuex';

const logger = createLogger({});
const store = createStore({
  plugins: [logger]
})

Pinia 状态管理库 ​

Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态,

语法示例 ​

  • App.vue
import { createApp } from "vue";
import { createPinia } from "pinia";

import App from "./App.vue";
import router from "./router";

const app = createApp(App);

app.use(createPinia());
app.use(router);

app.mount("#app");
  • stores/index.ts
import { reactive } from "vue";
import { defineStore } from "pinia";

import type { SCROLL_ROUTE_TYPE } from "@/constants/router";

export const storeMenu = defineStore("menu", () => {
  const menuList = reactive<SCROLL_ROUTE_TYPE[]>([]);

  const pushRoute = (item: SCROLL_ROUTE_TYPE) => {
    menuList.push(item);
  };

  const removeRoute = (index: number) => {
    menuList.splice(index, 1);
  };

  const clearRoute = () => {
    menuList.splice(0, menuList.length);
  };

  return { menuList, pushRoute, removeRoute, clearRoute };
});
  • 代码示例
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => {
    return { count: 0 }
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

// 读取
import { useCounterStore } from '@/stores/counter'
export default {
  setup() {
    const counter = useCounterStore()

    counter.count++
    counter.$patch({ count: counter.count + 1 })
    counter.increment()
  },
}

Released under the MIT License.