4.29 手写 vuex
let Vue
class Store{
constructor(options){
// step1 step1注册$store后让页面能正常显示state
// this.state = options.state
// step2实现mutations actions commit dispatch
// step2-01 初步实现mutations actions commit dispatch
this._mutations = options.mutations
this._actions = options.actions
// step2-02 锁死commit和dispatch的this指向
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
// step2-03 让state响应 触发render组件重新渲染
// 如何造响应式数据?
// 方式1:借鸡生蛋 - new Vue({data: {XXX: '/'}})
// 方式2:Vue.util.defineReactive(obj, 'XXX', '/')
// step2-03 让state变成响应式 同时state不可以随意改变
this._vm = new Vue({
data:{
// Vue约定:以 _ 或 $ 开头的属性 不会 被 Vue 实例代理
$$state : options.state
}
})
}
// step2-03 让state变成响应式 同时state不可以随意改变
get state(){
return this._vm._data.$$state
}
set state(v){
console.error('请使用replaceState重置状态');
}
// step2-01 初步实现mutations actions commit dispatch
commit(type,payload){
console.log('in commit:',this.state)
const mutation = this._mutations[type]
if(!mutation){
console.error('mutation不存在')
return
}
mutation(this.state,payload)
}
dispatch(type,payload){
const action = this._actions[type]
if(!action){
console.error('action不存在')
return
}
// 为什么第一个是this,也就是Store,因为action中需要commit,可以在Store拿到
action(this,payload)
// 报错 Cannot read property 'state' of undefined
// 由于dispatch通常是异步的,所以会异步commit。而commit依赖this.state,但是异步容易丢失上下文,所以我们在constructor中锁死commit和dispatch的this指向 ===》 step2-02
}
// OK step2已经完成 但是我们可以发现一个问题 页面上state不会变化,我们需要让Store.state变成响应式数据,触发Vue的render组件渲染 ===》step2-03
}
// 入口:install
function install(_Vue){
// 保存Vue
Vue = _Vue
// step1注册$store
Vue.mixin({
beforeCreate(){
/**
* this.$options用来访问main.js中
new Vue({
render: h => h(App),
store,
})中的options 这里我们是要拿到store
*/
if(this.$options.store)Vue.prototype.$store = this.$options.store
}
})
}
export default {Store,install}