zoukankan      html  css  js  c++  java
  • 了解Vuex4.x 简单实现原理

    参考文档:

    Vuex是什么

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

    这个状态自管理应用包含以下几个部分:

    • 状态,驱动应用的数据源;
    • 视图,以声明方式将状态映射到视图;
    • 操作,响应在视图上的用户输入导致的状态变化。

    Vuex的工作原理如下图所示:
    Vuex

    Vuex4.x的简单用法

    创建一个 store 实例

    import { createApp } from 'vue'
    import { createStore } from 'vuex'
    
    // 创建一个新的 store 实例
    const store = createStore({
      state () {
        return {
          count: 0
        }
      },
      getters: {
          double(state){
              return state.count * 2
          }
      },
      mutations: {
        increment (state, payload) {
          state.count++
        }
      },
      actions: {
         AsyncIncrement(state, payload){
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    commit('someMutation', payload)
                    resolve()
                }, 1000)
            })
         }
      }
    })
    
    const app = createApp({ /* 根组件 */ })
    
    // 将 store 实例作为插件安装
    app.use(store)
    

    通过组合式API的方法使用

    访问 State 和 Getter

    import { computed } from 'vue'
    import { useStore } from 'vuex'
    
    export default {
      setup () {
        const store = useStore()
    
        return {
          // 在 computed 函数中访问 state
          count: computed(() => store.state.count),
    
          // 在 computed 函数中访问 getter
          double: computed(() => store.getters.double)
        }
      }
    }
    

    访问 Mutation 和 Action

    import { useStore } from 'vuex'
    
    export default {
      setup () {
        const store = useStore()
    
        return {
          // 使用 mutation
          increment: () => store.commit('increment'),
    
          // 使用 action
          asyncIncrement: () => store.dispatch('asyncIncrement')
        }
      }
    }
    

    从用法上对比Vuex3.x

    • 创建 store 的方法不同,之前是通过new Store() 来创建一个 store实例。现在是通过 createStore 方法来创建。
    • Vuex4.x兼容之前的使用方法。但是在Vue3.x中如果我们想要通过组合式API的方法使用Vuex,我们需要借助与 useStore 这个函数。

    实现一个简单的 Vuex4.x;

    实现一个 createStore方法

    store实际上还是基于一个Class来实现的,只是没有直接将 Store 这个类暴露出来,而是包装成了一个函数,直接返回实例。

    import { reactive } from 'vue'
    
    export function createStore(options){
        return new Store(options)
    }
    
    class Store{
        constructor(options){
            const store = this;
            // 使用reactive使state是响应式的
            store._state = reactive({data: options.state})
        }
        get state(){ 
            return this._state.data
        }
    }
    
    

    通过 Object.defineProperty 来重新定义getters

    将用户传入的getters 全部定义到store实例的getters属性上,在获取值的时候调用

    function forEachValue(obj, fn){
        Object.keys(obj).forEach(key => fn(obj[key], key))
    }
    
    class Store{
        constructor(options){
            const store = this;
    
            // 使用reactive使state是响应式的
            store._state = reactive({data: options.state})
            
            // 保存getters
            const _getters = options.getters;
    
            store.getters = {};
    
            forEachValue(_getters, function(fn, key){
                Object.defineProperty(store.getters, key, {
                    get: ()=> fn(store.state),
                    enumerable: true
                })
            })
        }
    }
    

    基于发布订阅模式实现 mutationsactions

    class Store{
        constructor(options){
            // ...
            const store = this;
            store._mutations = Object.create(null)
            const _mutations = options.mutations;
    
            forEachValue(_mutations, (mutation, key)=>{
                store._mutations[key] = (payload) => {
                    mutation.call(store, store.state, payload)
                }
            })
        }
        commit = (type, payload) => {
            this._mutations[type](payload)
        }
    }
    

    Action 类似于 mutation,不同在于:

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作

    由于action可以执行异步函数,所以action在执行完成后应该返回一个Promise实例,对dispact的执行结果进行判断,如果不是一个Promise,需要给处理成一个promise。

    class Store{
        constructor(options){
            // ...
            const store = this;
    
            store._actions = Object.create(null)
    
            const _actions = options.actions;
        
            forEachValue(_actions, (action, key)=>{
                store._actions[key] = (payload) => {
                    const res = action.call(store, store.state, payload)
                    if(!isPromise(res)){
                        return Promise.resolve(res)
                    }
                    return res
                }
            })
        }
        dispatch = (type, payload) => {
            this._actions[type](payload)
        }
    }
    

    useStore

    通过inject来获取注册的store实例

    import {inject} from 'vue'
    export function useStore(injectKey = null) {
        return inject('store')
    }
    
    

    install

    在Vue项目中使用Vuex,我们需要通过use()来注册store

    
    const app = createApp({ /* 根组件 */ })
    
    // 将 store 实例作为插件安装
    app.use(store)
    
    
    class Store{
        install(app, injectKey){ 
            // Vue3.x createApp().use(store)
            // 全局暴露一个 变量,暴露的是store的实例
            app.provide('store')
    
            // Vue2.x Vue.prototype.$store = this
            // 增添$store属性 使得可以直接在模板中使用 $store.state.count
            app.config.globalProperties.$store = this;
        }
    }
    
    
  • 相关阅读:
    973. K Closest Points to Origin
    919. Complete Binary Tree Inserter
    993. Cousins in Binary Tree
    20. Valid Parentheses
    141. Linked List Cycle
    912. Sort an Array
    各种排序方法总结
    509. Fibonacci Number
    374. Guess Number Higher or Lower
    238. Product of Array Except Self java solutions
  • 原文地址:https://www.cnblogs.com/recode-hyh/p/15302642.html
Copyright © 2011-2022 走看看