1.思考:为啥vuex必须和vue使用而redux并不需要
vuex需要依赖vue是因为vuex是依赖vue而做到的响应式数据
但是redux是通过观察者的模式去实现的
2.vuex里如何实现响应式数据
通过借鸡生蛋的方式达到实现响应式数据
3.首先我们需要按照vue插件的格式要求写
//myVuex/myVuex.js
let Vue
class Store {
constructor(){
}
}
const install = function(vue_){
Vue = vue_
Vue.mixin({
beforeCreate(){
if(this.$options.store){
Vue.prototype.$store = this.$options.store //只是把store挂载在vue的原型链上
}
}
})
}
export default {Store,install}
4.定义一个store
//myVuex/index.js
import Vue from 'vue'
import Vuex from './myVuex.js'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
count : 1,
name : '我是高复古'
},
mutations:{
add(state,data){
state.count = state.count + data
}
},
actions:{
add({commit},data){
setTimeout(() => {
commit('add',2)
},1000)
}
},
getters:{
addCount(state){
return state.count+2
}
}
})
export default store
//main.js
import App from 'App.js'
import store from 'myVuex/index.js'
new Vue({
store,
render: h => {
return h(App)
},
}).$mount('#app')
//App.vue
<template>
<div @click="$store.commit('add',2)">
{$store.state.count}
</div>
<div @click="$store.dispatch('add',2)">
{$store.state.count}
</div>
<div>
{this.$store.$getters.addCount}
</div>
</template>
<script>
export default {
name:'App'
}
</script>
如何通过借鸡生蛋达成修改store的数据变为响应式数据
//myVuex/myVuex.js
let Vue
class Store {
constructor({state,getters,mutations,actions}){
//一般我们通过Vue.utils.defineReactive(this,'state',state)来生成响应式数据
//但是这里我们借用借鸡生蛋来做,是因为我们并不想用户直接可以修改state的数据
this._actions = actions
this._mutations = mutations
this._vm = new Vue({ //通过创建实例达到借鸡生蛋的目的
data(){
return {
$$state:state //$$可以防止代理
}
}
})
}
get state(){
return this._vm._data.$$state
}
set state(value){
throw Error('请不要直接修改state')
}
mutations(action,data){
const fn = this._mutations[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this._vm._data.$$state,data)//需要将state传入进去
}
}
}
const install = function(vue_){
Vue = vue_
Vue.mixin({
beforeCreate(){
if(this.$options.store){
Vue.prototype.$store = this.$options.store //只是把store挂载在vue的原型链上
}
}
})
}
export default {Store,install}
dispatch的实现
dispatch做的事情其实很简单就是通过action去找到对应的函数并把当前store的控制权给下去,需要特别注意由于dispatch在各种函数里调用,this指针可能会乱,所以我们需要使用bind绑定下this
class Store {
constructor({state,getters,mutations,actions}){
//一般我们通过Vue.utils.defineReactive(this,'state',state)来生成响应式数据
//但是这里我们借用借鸡生蛋来做,是因为我们并不想用户直接可以修改state的数据
this._actions = actions
this._mutations = mutations
this._vm = new Vue({ //通过创建实例达到借鸡生蛋的目的
data(){
return {
$$state:state //$$可以防止代理
}
}
})
this.dispatch = this.dispatch.bind(this)
this.commit = this.commit.bind(this)
}
get state(){
return this._vm._data.$$state
}
set state(value){
throw Error('请不要直接修改state')
}
dispatch(action,data){
const fn = this._actions[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this,data)//需要将state传入进去
}
},
mutations(action,data){
const fn = this._mutations[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this._vm._data.$$state,data)//需要将state传入进去
}
}
}
commit实现
和dispatch差不多就是传入的参数不一样,这个传入的是state
class Store {
constructor({state,getters,mutations,actions}){
//一般我们通过Vue.utils.defineReactive(this,'state',state)来生成响应式数据
//但是这里我们借用借鸡生蛋来做,是因为我们并不想用户直接可以修改state的数据
this._actions = actions
this._mutations = mutations
this._vm = new Vue({ //通过创建实例达到借鸡生蛋的目的
data(){
return {
$$state:state //$$可以防止代理
}
}
})
this.dispatch = this.dispatch.bind(this)
this.commit = this.commit.bind(this)
}
get state(){
return this._vm._data.$$state
}
set state(value){
throw Error('请不要直接修改state')
}
dispatch(action,data){
const fn = this._actions[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this,data)//需要将state传入进去
}
},
mutations(action,data){
const fn = this._mutations[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this._vm._data.$$state,data)//需要将state传入进去
}
}
}
getters的实现
也是通过vue实现,通过computed完成
首先我们需要将getters上的方法挂载在computed上,
其次我们需要将对应的值$store.getters.xxx对应成借鸡生蛋里的computed的属性值
class Store {
constructor({state,getters,mutations,actions}){
//一般我们通过Vue.utils.defineReactive(this,'state',state)来生成响应式数据
//但是这里我们借用借鸡生蛋来做,是因为我们并不想用户直接可以修改state的数据
this._actions = actions
this._mutations = mutations
this.getters = getters
const computed = {}
const store = this
//遍历getters将方法挂载在computed
Object.keys(this.getters).forEach(key => {
const fn = this.getters[key]
computed[key] = () => fn(this._vm._data.$$state) //computed的属性需要是个函数,所以需要这边使用高级函数
Object.defineProperty(this.getters,key,{
get(){
return store._vm[key]
}
})
})
this._vm = new Vue({ //通过创建实例达到借鸡生蛋的目的
data(){
return {
$$state:state //$$可以防止代理
}
}
})
this.dispatch = this.dispatch.bind(this)
this.commit = this.commit.bind(this)
}
get state(){
return this._vm._data.$$state
}
set state(value){
throw Error('请不要直接修改state')
}
dispatch(action,data){
const fn = this._actions[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this,data)//需要将state传入进去
}
},
mutations(action,data){
const fn = this._mutations[action]
if(!fn){
thorw error('你需要将此方法定义在你的actions里')
}else{
fn(this._vm._data.$$state,data)//需要将state传入进去
}
}
}