【Vue2.x】狀態管理Vuex

1. Website

image.png

Official Website: vuex.vuejs.org/#what-is-a-…

2. Install

npm install vuex@next --save

3. Introduction

3.0 Element

  • State : 提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,相似与data

  • Mutation : 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

  • Action : Action和Mutation相似,一般不用Mutation 异步操作,若要进行异步操作,使用Action

  • Getter : 类似于vue中的computed,进行缓存,对于Store中的数据进行加工处理形成新的数据

  • Modules : 当遇见大型项目时,数据量大,store就会显得很臃肿,为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

3.0.1 Constructure

vue2-demo 
├── public/                # static files 
│ ├── index.html           # 入口文件
│ └── favicon.ico          # title icon (可以多個,切換路由titile也切換) 
├── src/                   # project root 
│ ├── assets/              # images, icons, etc.靜態資源 
│ ├── api/                 # 封裝http 
│ ├── components/          # common components - 客製化頁面 
│ ├── layouts/             # layout containers -header, footer,sidebar, etc. 
│ ├── scss/                # scss styles 
│ ├── config/              # 封裝http 
│ │ └── httpConfig.ts      # axios 
│ ├── store/               # 全局狀態管理
│ │ ├── state.js         # 響應式數據
│ │ ├── actions.js        # 動態修改state的值
│ │ ├── getters.js        # 對state中的數據進行加工並形成新數據
│ │ ├── mutations.js      # 靜態修改state的值
│ │ ├── modules/         # 如果是大項目,進行切分
│ │ └── index.js         # 將前面所有js導入vuex
│ ├── i18n/ # 多語言切換 
│ │ ├── locales/ # 多語言切換 
│ │ │ ├── en.ts # 中文 
│ │ │ ├── zh.ts # 英文 
│ │ │ └── xxx.ts # 其他文 
│ │ └── index.ts # I18N切換 
│ ├── router/ # routes config
│ ├── views/pages # Route apge,路由導航的頁面 
│ │ ├── dashboard # 儀錶盤頁面 
│ │ ├── login # 登錄頁面、註冊頁面 
│ │ └── .... # etc.. 
│ ├── App.vue         # 三個標籤 template /script /style 
│ └── main.js         # 加載所有組件,掛載都index.html 
├── package.json      # dependency 
└── vue.config.js     # project config,install plugin,proxy

3.1 State

1.聲明全局變量

export const state = {
  loading: false,
  token: false,
  login: false,
  smallDevice: false,
  userProfile: {
    username: "",
    password: "",
    address: "",
    phone: "",
    age: 0
  },
  redirectUrl: "",
  result: []

2.使用

<p>{{$store.state.userProfile.username}}</p>
<p>{{$store.state.userProfile.password}}</p>
this.$store.state.userProfile.address
import {mapState} from "vuex";

<p>{{username + password + address}}</p>

computed: {
    ...mapState(["username","password","address"])
}

3.2 Mutation(Synchronous)

1.聲明

export const mutations = {
  addAge(state, num) {
    state.userProfile.age += state.userProfile.age + num
  },
  reduce(state) {
    state.userProfile.age --
  },
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}

2.使用

methods:{
    //加法
    btn(){
        this.$store.commit("addAge",10)
    }
    //减法
    btn1(){
        this.$store.commit("reduce") 
    }
}
import { mapMutations } from 'vuex'

export default {
  methods: {
    // 多個.
    ...mapMutations([
      'addAge', // map `this.addAge(num)` to `this.$store.commit('addAge',num)`
      'reduce', // map `this.reduce()` to `this.$store.commit('reduce')`
    ]),
    // 別名.
    ...mapMutations({
      add: 'increment' // map `this.add()` to `this.$store.commit('increment')`
    }),
    btn(){ 
        this.addAge(10)
    }
    btn1(){ 
        this.reduce()
    }
  }
}

3.3 Action(Asynchronous)

1.Simple

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
  //可以简写下面的形式
  actions: {
    increment ({ commit }) {
      commit('increment')
    }
  }
})

2.大项目分开写

export const setToken = ({ commit }, token) => {
  commit("setToken", token)
}
export const setLogin = ({ commit }, login) => {
  commit("setLogin", login)
}
export const setUserProfile = ({ commit }, userProfile) => {
  commit("setUserProfile", userProfile)
}
export const setRedirectUrl = ({ commit }, redirectUrl) => {
  commit("setRedirectUrl", redirectUrl)
}

3.使用

store.dispatch('increment')

4.也可以设定变数

function.js定义变数,然后调用方法时使用变数

export const TOKEN = "TOKEN"
export const LOGIN = "LOGIN"

3.4 Getter

1.Simple

const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos (state) {
      return state.todos.filter(todo => todo.done)
    }
    //getters也可以做参数传递
    doneTodosCount (state, getters) {
      return getters.doneTodos.length
    }
  }
})

2.大項目

export const getLoading = (state) => state.loading
export const getToken = (state) => state.token
export const getLogin = (state) => state.login
export const getUserProfile = (state) => state.userProfile
export const getRedirectUrl = (state) => state.redirectUrl

3.使用

store.getters.doneTodos
store.getters.doneTodosCount
import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
    // mix the getters into computed with object spread operator
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

3.5 Modules

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

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

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

store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state

3.6 index.js import

/src/store/index.js

import Vue from "vue"
import Vuex from "vuex"
import * as getters from "./getters.js"
import * as actions from "./actions.js"
import * as state from "./state.js"
import * as mutations from "./mutations.js"

// modules
import xxxModules from "./modules/xxxModule"

Vue.use(Vuex)

export default new Vuex.Store({
  state,
  actions,
  mutations,
  getters,
  modules: {
    xxxModules,
  }
})

/src/main.js

import App from "@/App"
import store from "@/store/index"
import router from "@/config/router"
import i18n from "@/config/lang"

new Vue({
  router,
  store,
  i18n,
  render: (h) => h(App),
}).$mount("#app")