状态管理Vuex全解

2019-05-22  本文已影响0人  YM雨蒙

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

vuex
  1. Vue Component --> dispatch 触发异步的 Actions
  2. Actions --> commit 触发同步的 Mutations
  3. Mutations --> 修改 State 里面的值
  4. State 修改以后 --> 会触发 Vue Component 视图的渲染

代码示意

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

import state from './state.js'
import getters from './getters.js'
import mutations from './mutations.js'
import actions from './actions.js'
import user from './module/user'

Vue.use(vuex)

export default new Vuex.Store({  // 创建vuex 实例
  // 参数传递
  state,
  getters,
  mutations,
  actions,
  modules: {
    user
  }
})

State

// store/state.js
const state = {
  // 数据源, 类似与 data
  appName: 'admin'
}
export default state
// store/module/user.js
const state = {
  userName: 'yym'
}
const getters = {
  // ...
}
const mutations = {
  // ...
}
const actions = {
  // ...
}

export default {
  // namespaced: true  命名空间
  state,
  mutations,
  actions
}
<template>
    <div>
        {{ appName }}
        {{ userName }}
    </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
    computed: {
        // 1. mapState 数组
        // ... 展开操作符, mapState返回一个对象, 把对象里的属性扁平化
        ...mapState([
            'appName',
        ]),

        // 2. 传入一个对象
        ...mapState({
            appName: state => state.appName,
            userName: state => state.user.userName
        }),

        // 使用
        appName () {
            return this.$store.state.appName
        },
        userName () {
            return this.$store.state.user.userName
        }
    }
}
</script>

Getter

类似于组件中的计算属性

// src/getters.js
const getters = {
  // 基于 appName 计算
  appNameWithVersion: (state) => {
    return state.appName + 'v2.0'
  }
}
export default getters
const state = {
    userName: 'yym'
}
// 可以用于多个组件
const getters = {
    firstLetter: state => {
        return state.userName.substr(0, 1)
    }
}
const mutations = {

}
const actions = {

}

export default {
    state,
    getters,
    mutations,
    actions
}
<template>
    <div>
        {{appNameWithVersion}}
        {{firstLetter}}
    </div>
</template>

<script>
import { mapState, mapGetters } from 'vuex'
export default {
    computed: {
        // 1. 传入数组
        ...mapGetters([
            'appNameWithVersion',
            'firstLetter'
        ]),

        // 计算属性中
        appNameWithVersion () {
            return this.$store.getters.appNameWithVersion
        }
    }
}
</script>

Mutation

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

import Vue from 'vue'

const mutations = {
    /**
        * @param {state}  第一个参数 state 同级的 state 对象
        * @params {params} 第二个参数, 文档中为载荷, 就是一个参数
        * params 1. 可以是一个值 2. 可以是一个对象
        */
    SET_APP_NAME (state, params) {
        // 1. 值
        state.appName = params

        // 2. 对象
        state.appName = params.appName
    },

    // 设置一个state 没有的值 version
    SET_APP_VERSION (state) {
        Vue.set(state, 'appVersion', 'v2.0')
    }
}

export default mutations
<template>
    <div>
        {{appName}}
        <button @click="hanlderChangeAppName">点击</button>
    </div>
</template>

<script>
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
    computed: {
        appName () {
            return this.$store.state.appName
        }
    },
    methods: {
        // 使用 mapMutations
        ...mapMutations([
            'SET_APP_NAME'
        ]),


        hanlderChangeAppName () {
            // this.appName = '新的值' 错误, 不能直接修改 state 的值

            // 1. 值的提交
            this.$store.commit('SET_APP_NAME', '新的值') // 第一个参数名称, 第二个为值

            // 2. 对象
            this.$store.commit({
                type: 'SET_APP_NAME',
                appName: '新的值'
            })

            // version
            this.$store.commit('SET_APP_VERSION')

            // 3. 对应mapMutations
            this.SET_APP_NAME('新的值')
        }
    }
}
</script>

Action

Action 类似于 mutation,不同在于:

  1. Action 提交的是 mutation,而不是直接变更状态。
  2. Action 可以包含任意异步操作
// app.js
export const getAppName = () => {
  return new Promise((resolve, reject) => {
        const err = null
        setTimeout(() => {
            if(!err) resolve({ code: 200, info: {appName: '新的值'}})
            else reject(err)
        })
    })
}
import { getAppName } from 'app.js'

const actions = {
    // 1. promise
    updateAppName ({ commit }) {
        getAppName().then(res => {
            console.log(res)
            const { info:{appName} } = res
            commoit('SET_APP_NAME', appName)
        }).catch(err => {
            console.log(err)
        })
    },

    // 2. async await
    async updateAppName({ commit }) {
        try {
            const { info:{appName} } = await getAppName()
            commoit('SET_APP_NAME', appName)
        } catch(err) {
            console.log(err)
        }
    }
}

export default actions
<template>
    <div>
        {{appName}}
        <button @click="hanlderChangeAppName">点击</button>
        <button @click="hanlderChangeUserName">点击</button>
    </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
    computed: {
        appName () {
            return this.$store.state.appName
        }
    },
    methods: {
        // 使用 mapMutations
        ...mapMutations([
            'SET_APP_NAME'
        ]),
        // 使用 mapActions
        ...mapActions([
            'updateAppName'
        ]),
        hanlderChangeAppName () {
            this.updateAppName()
        },
        hanlderChangeUserName () {
            this.$store.dispatch('updateAppName', '123')
        }
    }
}
</script>
上一篇 下一篇

猜你喜欢

热点阅读