框架中的状态管理

第一篇 vuex(请先看神图)

单项数据流
***
vuex管理流程

***

状态管理应用包含三部分:
  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。
进入实战
  • 在使用全局安装vue vue-cli
  • 使用vue全家桶指令vue create 项目名称
  • 安装vuex-- yarn add vuex

1.打开main.js文件,此为vue项目的入口在这个文件中,创建vue实例,并挂在其他模块插件,在new构造函数中挂载store,store为整个vuex仓库,还可以挂载router路由最后记住挂载根节点

import router from './router/'
import store from './store/'

new Vue({
    store,
    router,
    render(h) {
    return h(App)
}
}).$mount('#app')

2.创建与pages同级的文件夹store,创建index.js

  • 导入相应的包,并在Vue上使用Vuex
  • 创建Vuex实例 new Vuex.Store({})
  • 关键部分来了:在实例中定义Vuex灵魂部分state、getters、mutation、action、module,在后面会阐述,先看看我的简单布局

import Vue from 'vue'
import Vuex from 'vuex'
import http from '../utils/http'
Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        data: {}
    },
    getters: {
    },
    mutations: {
        setFirstData(state, result) {
            state.data = result
        },
    },
    actions: {
        async loadFirstData({commit}, params) {
            let result = await http.get(params.firstReq)
            commit('setFirstData', result)
        },  
    },
    module: {
        状态树
    } 
   })

export default store

3.看完大致结构,能帮助初学者快速搭建,当然每个单独的模块也可以单独定义在外面,再引入实例中。接下来我们来分别讲一讲五大核心的各自作用。

state

Vuex使用的单一状态树,在一个状态树中用一个对象,包裹着你定义的所有状态。
当数据量大,且分为不同模块时,我们还可以使用module,后面会讲到。

getter(getters)

相信在学Vuex之前,大家已经了解Vue中的计算属性,用来监控data中的状态是否发生变化。其实getters类似于计算属性computed,我们可以在该对象中定义多个方法,当state中的数据发生变化,函数就会执行并返回新的状态。
getter的返回值会根据他的依赖被缓存起来,且只有当它的依赖值发生变化才会被重新计算。
注意:getter中定义函数,函数的一个参数为state,及上面定义的状态。
Getter 也可以接受其他 getter 作为第二个参数。

mutation(mutations)

在Vuex中,想要更改store中的状态只有一个方法,那就是mutation。在mutation中你可以定义多个方法,这些方法的操作,最终是改变你在state中定义的属性,且这些方法接收state作为第一参数,当你想传入参数给该方法时,第二参数:载荷payload,该payload可以是对象或其他基本类型
方法(state,payload) { }
注意:mutation中确实是定义了很多方法,但你只能通过store.commit('方法名')来调用。mutation必须必须是同步函数,不要在方法中进行异步操作
支持的三种调用方式

store.commit({
  type: 'increment',
  amount: 10
})

store.commit('increment', {
  amount: 10
  })
  
store.commit('increment', 10)

action(actions)(详细再看vuex官网)

看完到上面mutation时,发现mutation有一个尴尬的地方,它只能进行同步操作,但我们往往需要请求接口资源,进行异步操作。action就是来弥补mutation的不足的地方,但在使用action有几个注意的地方。

  • 不要尝试在action中直接改变state中的状态。你也改不了。(#^.^#)
  • action提交的是mutation,而不是直接修改状态。
  • 通过context.commit(提交一个mutation方法)

摘抄点官方文档:
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

当然你也可以使用ES6的解构赋值 { xx } 将commit从context解构出来。
在所需组件中如何调用action方法:

store.dispatch('increment')

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
 })

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

module(此处还有许多细节请查看官网)

顾名思义:模块,解决最开始谈到的问题,Vuex维护的是一颗单一状态树,但当这颗状态树过于庞大时,就显得不好维护和提取所需属性。这个时候单一的状态树可以在分为多个模块,就像树的分支,在每一个单独的分支上,依旧有state,mutation,getter,action,module ,每个模块还可以在嵌套多个子模块。

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 的状态

对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:

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

如何在组件中使用

以上讲完store内部的定义和部分规则,那么到了实践者最关心的环节,如何在组件中使用vuex管理的状态和方法呢!
在Vuex中还有配对的4个方法,需要谁结构谁
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
    }
  })}

mapGetter

import { mapGetters } from 'vuex'

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

mapMutations

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }}

mapActions

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }}
Last modification:October 17th, 2019 at 12:27 am
同道中人,加个好友