【vuex源码实现】03.手写实现一个响应state的getter

文章首发: https://shudong.wang/10386.html
源码:https://github.com/wsdo/vuex-...

实现getter

当我们想实现getter的时候,先了解他的作用
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

实现思路

说白了,getter 就是把 state 经过一些逻辑过虑一下返回一个新的 state
这个逻辑 无非就是一个功能函数,so,我们应该实现一个函数,根据 state变化而变化
这时候,响应式数据的功劳 Object.defineProperty

首先我们来什么一个函数

接收参数
状态:因为我们要基于一个状态来处理返回一个状态所以需要一个状态
getter名字:我们在一个状态管理里面会有多个getter,所以会有getter名字,来区分
函数:因为我们要使用一个函数来处理一个逻辑,所以需要接收一个函数
函数如下
registerGetter(status,name,fn)
我们需要监听state状态,然后做出响应
const registerGetter = (store, fn, name) => {
  Object.defineProperty(store.getters, name, {
    get: () => {
      return fn(store.state)
    },
  })
}
初始化的时候,需要让我们所有的,getter函数执行
const forEachValue = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key))
下面是实现getter的全部代码 可以慢慢试着去理解分析

参考仓库:

main.js

import Vue from 'vue'
import App from './App.vue'
import stark from './store'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  stark,
}).$mount('#app')

Stark.vue

created() {
    console.log('getters',this.$stark.getters);
  },

打印结果

【vuex源码实现】03.手写实现一个响应state的getter

store/index.js

import Vue from 'vue'
import Vuex from '../store'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    count: 10,
  },
  getters: {
    getNumOne(state) {
      return state.count + 5
    },
  },
})

store.js

import applyMixin from './mixin'
import Vue from 'vue'
const forEachValue = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key))

const registerGetter = (store, fn, name) => {
  Object.defineProperty(store.getters, name, {
    get: () => {
      return fn(store.state)
    },
  })
}

const resetStoreVM = (store, state) => {
  store._vm = new Vue({
    data: {
      state: state,
    },
  })
}

export class Store {
  constructor(options = {}) {
    this.options = options
    this.getters = {}
    forEachValue(options.getters, (fn, name) => {
      registerGetter(this, fn, name)
    })
    resetStoreVM(this, options.state)
  }
  get state() {
    return this.options.state
  }
}

export const install = Vue => {
  applyMixin(Vue)
}

mixin.js

export default function(Vue) {
  Vue.mixin({ beforeCreate: starkInit })
  function starkInit() {
    const options = this.$options
    if (options.stark) {
      this.$stark = typeof options.stark === 'function' ? options.stark() : options.stark
    } else if (options.parent && options.parent.$stark) {
      this.$stark = options.parent.$stark
    }
  }
}

相关推荐