手搓 Vuex

手搓 Vuex

来自 知乎 的文章 手写Vuex核心原理

这里只放最终代码,了解详细内容请访问原文章,原作者写的肥肠好,顶顶顶

// store/myVuex.js
import Vue from "vue"

class Store {
    constructor(options) {
        this.vm = new Vue({
            data: {
                state: options.state || {}
            }
        })

        // 用户提供的 getters 函数
        const userGetters = options.getters || {}
        // Store 实例上的 getters 属性
        this.getters = {}
        // 遍历用户提供的 getter 函数,并为每个 getter 创建访问器属性
        Object.keys(userGetters).forEach(getterName => {
            Object.defineProperty(this.getters, getterName, {
                get: () => {
                    return userGetters[getterName](this.state)
                }
            })
        })

        // 用户提供的 mutations 函数
        const userMutations = options.mutations || {}
        // Store 实例上的 mutations 属性
        this.mutations = {}
        // 遍历用户提供的 mutations 函数,并为每个 mutation 创建访问器属性
        Object.keys(userMutations).forEach(mutationName => {
            this.mutations[mutationName] = arg => {
                userMutations[mutationName](this.state, arg)
            }
        })

        const userActions = options.actions || {}
        this.actions = {}
        Object.keys(userActions).forEach(actionName => {
            this.actions[actionName] = arg => {
                userActions[actionName](this, arg)
            }
        })

    }

    dispatch(method, arg) {
        this.actions[method](arg)
    }

    // 在执行 dispatch 调用 commit,this undefined 改为箭头函数
    commit = (method, arg) => {
        this.mutations[method](arg)
    }

    get state() {
        return this.vm.state
    }
}

const install = function(Vue) {
    Vue.mixin({
        beforeCreate() {
            if(this.$options && this.$options.store) { // 如果是根组件
                this.$store = this.$options.store
            } else { // 如果是子组件
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

const Vuex = {
    Store,
    install
}

export default Vuex
// store/index.js
import Vue from "vue"
import Vuex from './myVuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        num: 0
    },
    getters: {
        getNum: state => {
            return state.num
        }
    },
    mutations: {
        incre(state, arg) {
            state.num += arg
        }
    },
    actions: {
        asyncIncre({commit}, arg) {
            setTimeout(() => {
                commit('incre', arg)
            }, 1000)
        }
    },
    modules: {}
})
// App.vue
<script lang="ts">
export default {
	name: "App",
	computed: {},
	methods: {
		add() {
			this.$store.commit("incre", 1);
		},
		asyncAdd() {
			this.$store.dispatch("asyncIncre", 2);
		},
	},
};
</script>

<template>
	<div id="app">
		123
		<p>state:{{ this.$store.state.num }}</p>
		<p>getter:{{ this.$store.getters.getNum }}</p>
		<button @click="add">+1</button>
		<button @click="asyncAdd">异步+2</button>
	</div>
</template>

<style lang="scss" scoped>
</style>
// main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值