vuex笔记

早过忘川 提交于 2020-01-21 18:52:26

State

定义State

const store = new Vuex.Store({
    state: {
        todos: [
            { id: 1, text: '...', done: true },
            { id: 2, text: '...', done: false }
        ]
    }
})

State获取

// 实例获取 
store.state.count

// 组件中获取
this.$store.state.count

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
        }
    })
}

使用扩展运算符

export default {
    computed: {
        localComputed () {},
        ...mapState({
             // 使用扩展运算符进行state混入
        })
    }
}

Getter

定义Getter

const store = new Vuex.Store({
    getters: {
        doneTodos: state => {
            return state.todos.filter(todo => todo.done)
        }
    }
})

Getters获取

// 实例中获取
store.getters.count

// 组件中获取
this.$store.getters.count

Getters访问

// 属性访问
const store = new Vuex.Store({
    getters: {
        doneTodos: state => state.todos,
        doneTodosCount: (state, getters) => {
            return getters.doneTodos.length
        }
    }
})

// 方法访问
const store = new Vuex.Store({
    getters: {
        getTodoById: (state) => (id) => {
            return state.todos.find(todo => todo.id === id)
        }
    }
})

store.getters.getTodoById(2)

mapGetters辅助函数

import { mapGetters } from 'vuex'

export default {
    computed: {
        // 使用扩展运算符进行getters混入
        ...mapGetters([
            "doneTodosCount",
            "anotherGetter"
        ])
        // 对getters取别名
        mapGetters({
            // 把this.doneCount映射为this.$store.getters.doneTodosCount
            doneCount:"doneTodosCount"
        })
    }
}

Mutation

定义Mutation

const store = new Vuex.Store({
    mutations: {
        increment (state, payload) {
            // 变更状态
            state.count++
        }
    }
})

提交Mutation

// payload为载荷
store.commit('increment', payload)

// 载荷形式
store.commit('increment', {
    amount: 10
})

// 对象形式
store.commit({
    type: 'increment',
    amount: 10
})

mapMutations辅助函数

import { mapMutations } from 'vuex'

export default {
    methods: {
        ...mapMutations([
            "increment",    // 将this.increment()映射为this.$store.commit('increment')
            "incrementBy"   // 将this.incrementBy(amount)映射为this.$store.commit('incrementBy', amount)
        ]),
        ...mapMutations({
            add: 'increment' // 将this.add()映射为this.$store.commit('increment')
        })
    }
}

注意

  • mutation应该专注同步事务

  • 应该使用大写常量表示Mutation事件类型

Action

定义Action

const store = new Vuex.Store({
    actions: {
        increment1 (context) {
            // context为与store类似的对象
            context.commit('increment')
        },
        increment2 ({ commit }) {
            // 可以对context解构赋值
            setTimeout(() => {
                // action层的好处在于,可以进行异步处理
                commit('increment')
            }, 1000)
        }
    }
})

分发Action

store.dispatch('increment')

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

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

mapActions辅助函数

import { mapActions } from 'vuex'

export default {
    methods: {
        ...mapActions([
            "increment", // 将this.increment()映射为this.$store.dispatch('increment')
            "incrementBy" // 将this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)
        ]),
        ...mapActions({
            add:"increment" // 将this.add()映射为this.$store.dispatch('increment')
        })
    }
}

组合Action

  • store.dispatch接受从action方法中返回的Promise

  • 组合实例one

actions: {
    actionA ({ commit }) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                commit('someMutation')
                resolve()
            }, 1000)
        })
    }
}

store.dispatch('actionA').then(() => {
    // ...
})

// 在另外一个action中也可以
actions: {
    actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
            commit('someMutation')
        })
    }
}
  • 组合实例two
actions: {
    async actionA ({ commit }) {
        commit('gotData', await getData())
    },
    async actionB ({ dispatch, commit }) {
        await dispatch('actionA') // 等待actionA完成
        commit('gotOtherData', await getOtherData())
    }
}

Module

基本使用

const store = new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    }
})

模块的局部状态

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

  • 模块内部的action,局部状态通过context.state访问,根节点状态则为context.rootState

命名空间

  • 通过模块内添加namespaced: true属性实现

  • 使用模块内容时,不需要在同一模块内额外添加空间名前缀

命名空间模块——访问全局内容

  • getter中,rootState和rootGetter会作为第三和第四参数传入

  • action中,通过context对象的属性传入action

  • 全局分发action或提交mutation,将{ root: true }作为第三参数传给dispatch或commit即可

命名空间模块——注册全局action

{
    actions: {
        someOtherAction ({dispatch}) {
            dispatch('someAction')
        }
    },
    modules: {
        foo: {
            namespaced: true,
            actions: {
                someAction: {
                    root: true,
                    handler (namespacedContext, payload) {} // -> 'someAction'
                }
            }
        }
    }
}

命名空间的绑定函数

// 繁琐用法
computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  })
},
methods: {
  ...mapActions([
    'some/nested/module/foo',
    'some/nested/module/bar'
  ])
}

// 简洁用法
computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo',
    'bar'
  ])
}

// createNamespacedHelpers用法
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

模块动态注册

  • 动态注册myModule模块
   store.registerModule('myModule', {})
   store.registerModule(['nested', 'myModule'], {}) // 注册嵌套模块nested/myModule
  • 可以使用store.unregisterModule('myModule')来动态卸载模块(不能卸载静态模块)

  • 如果想保留过去的state,可以通过 preserveState选项将其归档

   store.registerModule('a', module, { preserveState: true })

模块重用

const MyReusableModule = {
  state () {
    return {
      foo: 'bar'
    }
  },
  // mutation, action 和 getter 等等...
}

项目结构

  • vuex并不限制你的代码结构,但它规定了一些需要遵守的规则

    • 应用层级的状态应该集中到单个store对象中

    • 提交mutation是更改状态的唯一方法,并且这个过程是同步的

    • 异步逻辑都应该封装到action里面

插件

基本用意

  • vuex的store接受plugins选项,这个选项暴露出每次mutation的钩子

  • vuex插件就是一个函数,它接收store作为唯一参数

  • 基本使用

const myPlugin = store => {
    // 当store初始化后调用
    store.subscribe((mutation, state) => {
        // 每次mutation之后调用
        // mutation的格式为{ type, payload }
    })
}

const store = new Vuex.Store({
    // ...
    plugins: [myPlugin]
})

在插件内提交Mutation

  • 在插件中不允许直接修改状态,类似于组件,只能通过提交mutation来触发变化

  • 通过提交mutation,插件可以用来同步数据源到store

  • 以同步websocket数据源到store为例

export default function createWebSocketPlugin (socket) {
    return store => {
        socket.on('data', data => {
            store.commit('receiveData', data)
        })
        store.subscribe(mutation => {
            if (mutation.type === 'UPDATE_DATA') {
                socket.emit('update', mutation.payload)
            }
        })
    }
}

const plugin = createWebSocketPlugin(socket)
const store = new Vuex.Store({
    state,
    mutations,
    plugins: [plugin]
})

生成State快照

  • 对state状态对象进行深拷贝

  • 生成状态快照的插件应该只在开发阶段使用

  • 使用webpack或Browserify,让构建工具帮我们处理

const store = new Vuex.Store({
    plugins: process.env.NODE_ENV !== 'production' ? [myPluginWithSnapshot] : []
})

内置Logger插件

  • 如果正在使用vue-devtools,则不需要此插件

  • logger插件会生成状态快照,所以仅在开发环境使用

  • 可以直接通过script标签引入,它会提供全局方法createVuexLogger

  • 基本使用

import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
    plugins: [createLogger()]
})

const logger = createLogger({
    // 自动展开记录的 mutation
    collapsed: false, 
    filter (mutation, stateBefore, stateAfter) {
        // 若 mutation 需要被记录,就让它返回true即可
        // 顺便,`mutation` 是个{ type, payload }对象
        return mutation.type !== "aBlacklistedMutation"
    },
    transformer (state) {
        // 在开始记录之前转换状态
        // 例如,只返回指定的子树
        return state.subTree
    },
    mutationTransformer (mutation) {
        // mutation 按照{ type, payload }格式记录
        // 我们可以按任意方式格式化
        return mutation.type
    },
    // 自定义console实现,默认为console
    logger: console
})

严格模式

  • 严格模式下,无论何时发生了状态变更且不是由mutation函数引起的,将会抛出错误

  • 严格模式能保证所有的状态变更都能被调试工具跟踪到

  • 示例代码

const store = new Vuex.Store({
    // ...
    strict: true
})

表单处理

  • 处理方式一
// 组件中
<input :value="message" @input="updateMessage">
{
   computed: {
    ...mapState({
       message: state => state.obj.message
    })
   },
   methods: {
    updateMessage (e) {
       this.$store.commit('updateMessage', e.target.value)
    }
   }
}

// store中
mutations: {
    updateMessage (state, message) {
    state.obj.message = message
}
  • 处理方式二
<input v-model="message">

computed: {
    message: {
        get () {
            return this.$store.state.obj.message
        },
        set (value) {
            this.$store.commit('updateMessage', value)
        }
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!