zoukankan      html  css  js  c++  java
  • vuex简介

    1.简介

    vuex是 vue官方推荐的一个状态管理器。当我们遇到很多状态改变时,组件之间的通信就会变得复杂,这时候vuex的强大就展现出来。

    我们从vuex的原理以及vuex的api两个部分介绍vuex

    原理:

    vuex的核心是store对象,它承载了vue的状态管理。vuex的实现分为了2个部分,第一个部分是store的创建,以及第二部分store的挂载,并且解析store。

    vuex通过插件安装的形式来使得vue挂载vuex的store,当然这个是在vue组件的createBefore阶段实现的。随后Vuex将它直接挂载到 $options.$store 以供使用vue使用。

    对于vuex的属性,Vuex 会将 vuex 属性解构成 getters 和 actions。并将 getters 的每个属性都挂载 vm 下(有可能被组件的 $options.data() 的属性覆盖),同时定义每个值的 getter 方法,但并不会定义 setter 方法,这是因为根据 Vuex 的设计是不允许开发者直接在组件内更改 store.state,而对数据的改动要通过提交 mutation。Vuex 实际上将 vm.vuex.getter 内的属性当作当前 vm 的计算属性来处理。和计算属性的区别是计算属性依赖计算的是 vm.$options.data 内的值,而 vm.vuex.getter 的属性依赖计算的是 store._vm.$options.data。这样所有组件的渲染都将都可以直接从状态树拿数据来渲染 UI 。

    所有的组件都可以和vuex的状态树进行数据交互。但是不允许直接改变状态树的状态,应该用vuex的mutations来提交状态的改变。vuex会将actions内的方法绑定到vue的$options.methods下,它们与vue中定义的方法并没有区别。而 actions 内的方法将通过 dispatch 触发 mutations 来更新全局状态,actions方法与mutations的区别是,mutations改变state并且必须是同步改变,而actions可以作为异步提交的方法,dispatch 可以接收一个promise,并且返回一个promise。

    2.API:

    state:在vue中引入store对象,在子组件中通过this.$store来访问vuex中状态,并且我们最好在vue的computed中获取vuex的状态。

    mapState:这是一个语法糖,可以快捷的获取更多的state。

    接受一个object参数:

    复制代码
    // 在单独构建的版本中辅助函数为 Vuex.mapState
    import { mapState } from 'vuex'
    
    export default {
      // ...
      computed: mapState({
        // 箭头函数可使代码更简练
        count: state => state.count,
    
        // 传字符串参数 'count' 等同于 `state => state.count`
        countAlias: 'count',
    
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        countPlusLocalState (state) {
          return state.count + this.localCount
        }
      })
    }
    复制代码

    当计算属性的名称和节点名称相同时,也可以接受一个数组对象。

    computed: mapState([
      // 映射 this.count 为 store.state.count
      'count'
    ])

    对象展开:合成最终的computed属性

    复制代码
    computed: {
      localComputed () { /* ... */ },
      // 使用对象展开运算符将此对象混入到外部对象中
      ...mapState({
        // ...
      })
    }
    复制代码

    getter:store的计算属性,在获取数据的时候,我们可以通过getter进行数据的操作,在相同地方用到的数据操作就不需要写一个公用的处理函数。它接受2个参数,state和getters。

    复制代码
    getters: {
      // ...
      doneTodosCount: (state, getters) => {
        return getters.doneTodos.length
      }
    }
    store.getters.doneTodosCount // -> 1
    复制代码

    mapGetters:

    复制代码
    export default {
      // ...
      computed: {
      // 使用对象展开运算符将 getters 混入 computed 对象中
        ...mapGetters([
          'doneTodosCount',
          'anotherGetter',
          // ...
        ])
      }
    }
    复制代码

    或者

    mapGetters({
      // 映射 this.doneCount 为 store.getters.doneTodosCount
      doneCount: 'doneTodosCount'
    })

    mutations:vuex提交状态的唯一方式。mutations更像一个事件监听器,当vue中commit了信息之后,相应的mutation才会执行相应的回掉函数。它接受2个参数,state和object。

    因为vue是响应式的,所以mutations也应该遵守vue的动态绑定,所以在需要使用mutations前,尽量初始化。或者是添加时使用vue.set(obj,'new obj', 'value')或者以新运算符state.obj = { ...state.obj, newProp: 123 }

    mutations必须是同步函数

    组件中提交mutations:

    复制代码
    import { mapMutations } from 'vuex'
    
    export default {
      // ...
      methods: {
        ...mapMutations([
          'increment' // 映射 this.increment() 为 this.$store.commit('increment')
        ]),
        ...mapMutations({
          add: 'increment' // 映射 this.add() 为 this.$store.commit('increment')
        })
      }
    }
    复制代码

    actions: actions提交的是mutations,因为mutations是必须为同步状态,actions就提供了一种异步的形式提交mutations,我们可以在active中去做异步处理,并且提交mutation。它接受一个context参数,这个参数具有store对象相同属性和方法,但是并不是store本身。

    复制代码
    actions: {
        increment (context) {
          context.commit('increment')
        }
      }

    //或者 使用解值
    actions: {
      increment ({ commit }) {
        commit('increment')
      }
    }

    复制代码

    actions以dispatch来分发

    复制代码
    // 以载荷形式分发
    store.dispatch('incrementAsync', {
      amount: 10
    })
    
    // 以对象形式分发
    store.dispatch({
      type: 'incrementAsync',
      amount: 10
    })
    复制代码

    组合的actions:

    store.dispatch 可以处理被触发的action的回调函数返回的Promise,并且store.dispatch仍旧返回Promise

    复制代码
    actions: {
      actionA ({ commit }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            commit('someMutation')
            resolve()
          }, 1000)
        })
      }
    }
    // 可以这样触发
    //
    一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
    store.dispatch('actionA').then(() => {
      // ...
    })

    // 也可以这样子触发
    actions: {
    // ...
      actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
          commit('someOtherMutation')
        })
      }
    }


    复制代码

    modules:

    Vuex 允许我们将 store 分割到模块(module)。每个模块拥有自己的 state、mutation、action、getters、甚至是嵌套子模块——从上至下进行类似的分割。

    复制代码
    const moduleA = {
      state: { ... },
      mutations: { ... },
      actions: { ... },
      getters: { ... }
    }
    
    const moduleB = {
      state: { ... },
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        a: moduleA,
        b: moduleB
      }
    })
    
    store.state.a // -> moduleA 的状态
    store.state.b // -> moduleB 的状态
    复制代码

    模块的局部状态

    对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态。

    复制代码
    const moduleA = {
      state: { count: 0 },
      mutations: {
        increment (state) {
          // state 模块的局部状态
          state.count++
        }
      },
    
      getters: {
        doubleCount (state) {
          return state.count * 2
        }
      }
    }
    复制代码

    对于模块内部的 action,context.state 是局部状态,根节点的状态是 context.rootState。

    复制代码
    const moduleA = {
      // ...
      actions: {
        incrementIfOddOnRootSum ({ state, commit, rootState }) {
          if ((state.count + rootState.count) % 2 === 1) {
            commit('increment')
          }
        }
      }
    }
    复制代码

    对于模块内部的 getter,根节点状态会作为第三个参数。

    复制代码
    const moduleA = {
      // ...
      getters: {
        sumWithRootCount (state, getters, rootState) {
          return state.count + rootState.count
        }
      }
    }
    复制代码

    命名空间:

    模块内部的 action、mutation、和 getter 现在仍然注册在全局命名空间——这样保证了多个模块能够响应同一 mutation 或 action。你可以通过添加前缀或后缀的方式隔离各模块,以避免名称冲突。你也可能希望写出一个可复用的模块,其使用环境不可控。例如,我们想创建一个 todos 模块:

    复制代码
    // types.js
    
    // 定义 getter、action、和 mutation 的名称为常量,以模块名 `todos` 为前缀
    export const DONE_COUNT = 'todos/DONE_COUNT'
    export const FETCH_ALL = 'todos/FETCH_ALL'
    export const TOGGLE_DONE = 'todos/TOGGLE_DONE'
    // modules/todos.js
    import * as types from '../types'
    
    // 使用添加了前缀的名称定义 getter、action 和 mutation
    const todosModule = {
      state: { todos: [] },
    
      getters: {
        [types.DONE_COUNT] (state) {
          // ...
        }
      },
    
      actions: {
        [types.FETCH_ALL] (context, payload) {
          // ...
        }
      },
    
      mutations: {
        [types.TOGGLE_DONE] (state, payload) {
          // ...
        }
      }
    }
    复制代码

    我们也可以运用es6的新方法,symbol做命名;

    需要了解更多关于symbol的信息,请移步阮一峰老师的ES6

  • 相关阅读:
    Python 之nmap模块问题解决
    phpstudy --mysql支持外联。
    Kali 更新
    Win 10 访问IPV6地址 问题。
    Macbookpro 使用Parallels Deskop安装kali Parallels Tools
    Windows 转 Mac 利用git继续管理github
    shell脚本移植问题(windwos移植到linux)
    APP测试项总结
    apktool 反编译
    微信小程序-服务器返回数据中包含有 换行符失效问题解决方案
  • 原文地址:https://www.cnblogs.com/jinly/p/9492518.html
Copyright © 2011-2022 走看看