vuex 大法(全)

vuex

背景

当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

  • 多个视图依赖于同一状态。
  • 来自不同视图的行为需要变更同一状态。

对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

上面说了对应多组件共享数据的两种处理方式
1,使用多层传值。显然,但需要修改其中一层的数据或者说可能去掉该页面时,需要从新去理清数据的传递,如果是一个你觉得可能没啥,那如果变量多了,再去清理是很浪费时间的
2. 使用事件监听,比如 eventEmitter 或者 bus总线 去处理。那么需要占据资源,需要考虑释放资源以免内存溢出。再者,如果该逻辑去除或者改动,都需要去页面查找对应的监听和接收函数去修改对应的代码,代码分散,不好管理。
以上,你需要采用vuex了。

vuex的基本思想

我们把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!

通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。

适应性

中大型单页应用适用

那么,如果我平时也使用vuex去存数据行吗?也可以。但是有必要吗?没有。因为写起来其实不好写,每次定义好变量后还要去页面再引入一次,工作量也大。其二,这样会导致修改变量名可能需要修改多处,state, mutation, action, data, methos里面的方法名,改一个动全身。如果没有洁癖可以忽略该修改。

各个概念

state

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

也就是说

1. state里面的值是响应式的

2. 改变state的唯一方式是使用commit mutation。因为我们想要更明确地追踪到状态的变化。

getter

可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算

mutation

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

mutation 必须是同步函数

action

Action 提交的是 mutation,而不是直接变更状态。

Action 可以包含任意异步操作

模块化

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)

用法

目录结构

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:

└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── m1.js       # 用户模块
        └── m2.js   # 产品模块
m1.js 示例
import * as api from '../../api/m1'
// import * as TYPE from './mutation-types'
// import { SOME_MUTATION } from './mutation-types'

// 初始化 state
// shape: [{ id, quantity }]
const state = {
  clickNumber: 1,
  othorVar: null
}

// getters
const getters = {
  count: (state, getters, rootState) => {
    return state.clickNumber + 1
  },
}

// mutations
const mutations = {
  // 使用常量替代 Mutation 事件类型
  // 使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
  [TYPE.SOME_MUTATION] (state, obj) {
    state.clickNumber = obj.click
    state.othorvar = obj.othorvar
  },
}

// actions
const actions = {
  // 命名使用a开头的驼峰写法。
  // 1. 使用promise 
  aAdd ({ state, commit }, params1, params2, ...) {
    return new Promise((resolve, reject) => {
        api.getxxx( (result) => {
            // coding..
    		commit('SOME_MUTATION', result)
            resolve(result)
        })
    })
  }// 2. 使用async await 
  async aDel ({ state, commit }, params ) {
      await result = api.getxxx()
      // coding.. 对r的处理等。
      commit('SOME_MUTATION', result)
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}
mutation-types.js 示例
// mutation-types.js 这里写mutation的方法名,避免冲突,方便查找 全部大写并使用下划线连接单词。
// goods
export const SOME_MUTATION = 'SOME_MUTATION'
// news
export const SOME_MUTATION = 'SOME_MUTATION'
moduls/xxx.js 示例
import Vue from 'vue'
import Vuex from 'vuex'
import m1 from './modules/m1'
import m2 from './modules/m2'
// 更多模块...
Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
  modules: {
    m1,
    m2,
   // 更多模块...
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})
组件内使用
import {
    mapState,
    mapMutations,
    mapGetters,
    mapActions
} from 'vuex'
export default {
    ...
    computed: {
        ...mapState('命名空间名', [
            // 1. 映射 this.state1 为 store.state.state1 【一般使用这种写法方便简洁。
            'state1',
            'state2'
            // 2. 起别名写法
            a: 'state1',
            b: 'state2'
            // 3. 使用this写法 【需要和本地data一起处理state的数据时候使用这种写法。
            fn(state) {
        		return state.state1 + this.xxx
    		}
            ...
        ]),
        ...mapGetters('命名空间名', [
            'getter1',
            'getter2'
            ...
        ]),
		...
    }
    methods: {
        ...
        ...mapMutations('命名空间名', [
            'mutation1',
            'mutation2'
            ...
        ]), 
         ...mapActuons('命名空间名', [
            'action1',
            'action2'
            ...
        ]),
            ...
    }
    ...
}

你真的会vuex吗?会下面的使用你才算真的全会了

跨模块调用

const { commit, dispatch, state, rootState, rootGetters } = store

action 里面获取其他模块的getter
rootGetters['vip/get']

action 里面触发其他模块的mutation 
commit('vip/receive', data, {root: true})

action 里面调用其他模块的 actions
dispatch('vip/get', {}, {root: true})
原文地址:https://www.cnblogs.com/huangjunjia/p/13068162.html