手写vuex4源码(五)模块实现原理

一、前文梳理

流程:

  • vuex暴露两个方法createStoreuseStore
  • 调用createStore传递过来所有的state、getters、mutations
  • createStore中调用 new Store方法,产生store实例,传递用户定义的所有的数据
  • new Store中的install方法会把store实例放在全局上,确保每个组件可以通过$store访问,同时通过app.provide(injectKey || storeKey, this)把store放到app上
  • new Store调用new ModuleCollection继续传递数据,ModuleCollectionregister方法把数据变成一个root树
  • new StoreinstallModule方法把state、getters、mutations等按照模块划分好
  • useStore把当前store注入每个组件:组件中会const store = useStore();

目前状态:
假如每个模块都有同名的add方法,调用时,每一个都会触发

二、实现逻辑

当用户调用方法时,想要实现调用哪个就触发对应的方法,使用发布订阅模式

三、收集getters、mutations、actions

把所有的getters、mutations、actions收集到store

1、在store中创建收集容器

constructor(options) {
        const store = this
        // options是一个对象,对象中有state、modules等
        // 发布订阅模式,用户触发哪个就去调用哪个
        store._modules = new ModuleCollection(options)
        store._wrappedGetters = Object.create(null);
        store._mutations = Object.create(null);
        store._actions = Object.create(null);
}

2、定义辅助方法

在modules.js中定义方法

forEachGetter(fn){
        if(this._raw.getters){
            forEachValue(this._raw.getters,fn)
        }
    }
    forEachMutation(fn){
        if(this._raw.mutations){
            forEachValue(this._raw.mutations,fn)
        }
    }
    forEachAction(fn){
        if(this._raw.actions){
            forEachValue(this._raw.actions,fn)
        }
    }

3、实现收集

在安装时,把所有的对象放到store对应定义的变量上

(1)getter

getter第一个参数为state,此处用store.state因为后续我们会将store.state 用reactive包裹,把数据变成响应式

 // 安装的时候 把所有的对象放到store对应定义的变量上,遍历当前模块上所有的getter,
    // getters  module._raw.getters
    module.forEachGetter((getter, key) => { // {double:function(state){}}
        // 第一个参数是getter的内容,key为getter的属性名,再去调用原来的方法,
        // store._wrappedGetters[key] = getter   这样写没有办法传递参数
        store._wrappedGetters[key] = () => {
            // 通过这个方法去获取最新的state
            // 第一个参数为state,写module.state问题:模块上的状态是自己维护的,不具备响应式的功能
            return getter(getNestedState(store.state, path)); 
        }
    })
function getNestedState(state, path) { // 根据路径 获取store.上面的最新状态
    return path.reduce((state, key) => state[key], state)
}
(2)mutation
// mutation   {add:[mutation]}
  module.forEachMutation((mutation, key) => {
    const entry = store._mutations[key] || (store._mutations[key] = []);
    // 把当前的mutation放到entry里面
    // 用户store.commit('add',payload),调用entry里面的方法,payload作为参数传递进来
    entry.push((payload)=>{ 
        // call:改变this的指向同时让函数mutation立即执行,第一个参数为最新的state,第二个为用户传递的参数
        mutation.call(store, getNestedState(store.state, path), payload)
    })
  });
(3)action
  • mutation和action的一个区别, action执行后返回一个是promise,需要判断用户是否写了.then方法
  • action既可以调用commit又可以调用dispatch,所以区别于mutation第一个参数传递store
//   // store.dispatch('LOGIN',payload).then(()=>{})
  module.forEachAction((action, key) => {
    const entry = store._actions[key] || (store._actions[key] = []);
    // 用户store.dispatch('add',payload),调用entry里面的方法,payload作为参数传递进来
    entry.push((payload)=>{ 
        // action既可以调用commit又可以调用dispatch,所以第一个参数传递store
        let res = action.call(store, store, payload)
        // res 是不是一个promise
        if (!isPromise(res)) {
            return Promise.resolve(res);
        }
        return res;
    })
  });

utils中扩展工具类,判断返回值是不是一个promise

export function isPromise(val) {
  return val && typeof val.then === "function";
}

在这里插入图片描述

4、实现

(1)定义state和getters

new Store中,定义响应式数据

// 定义响应式数据
    resetStoreState(store,state);
    
	get state(){ //目前数据在data中
    	return this._state.data
  }
// 定义响应式数据
  unction resetStoreState(store, state) {
  // 为了后续变的方便,包一层data
  store._state = reactive({ data: state }); //store._state.data = 'xxx'
  const wrappedGetters = store._wrappedGetters;
  // 循环把每一个
  store.getters = {};
  forEachValue(wrappedGetters, (getter, key) => {
    Object.defineProperty(store.getters, key,{
      get: () => getter(),
      enumerable: true
    });
  });
(2)commit和dispatch

在_mutations和_actions中找到对应的方法去触发

commit = (type, payload) => {
    const entry = this._mutations[type] || [];
    entry.forEach((handler) => handler(payload));
  };
  dispatch = (type, payload) => {
    // 执行完之后是promise
    const entry = this._actions[type] || [];
    return Promise.all(entry.map((handler) => handler(payload)));
  };
(3)测试
actions: {
    //可以调用其他action和mutation
    asyncAdd({ commit }, payload) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          commit("add", payload);
          resolve('ok')
        }, 1000);
      });
    },
  },
function asyncAdd(){
      store.dispatch('asyncAdd',1).then(res=>{
        console.log(res)
      })
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
<项目介绍> 基于Java实现手写汉字识别系统源码(毕业设计).zip基于Java实现手写汉字识别系统源码(毕业设计).zip基于Java实现手写汉字识别系统源码(毕业设计).zip 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到94.5分,放心下载使用! 该资源适合计算机相关专业(如人工智能、通信工程、自动化、软件工程等)的在校学生、老师或者企业员工下载,适合小白学习或者实际项目借鉴参考! 当然也可作为毕业设计、课程设计、课程作业、项目初期立项演示等。如果基础还行,可以在此代码基础之上做改动以实现更多功能。 基于Java实现手写汉字识别系统,不使用机器学习的方法,而是使用0-1矩阵的文件来保存手写体的字形,再通过欧氏距离计算出可能的字符,是一个比较简单的手写识别系统,可以比较准确的识别出大多数的常用汉字。 基于Java实现手写汉字识别系统,不使用机器学习的方法,而是使用0-1矩阵的文件来保存手写体的字形,再通过欧氏距离计算出可能的字符,是一个比较简单的手写识别系统,可以比较准确的识别出大多数的常用汉字。 基于Java实现手写汉字识别系统,不使用机器学习的方法,而是使用0-1矩阵的文件来保存手写体的字形,再通过欧氏距离计算出可能的字符,是一个比较简单的手写识别系统,可以比较准确的识别出大多数的常用汉字。
手写一个Spring的源码实现是一个非常复杂的任务,需要对Spring的核心原理和设计思想有深入的理解。以下是一个简单的Spring源码实现的示例,仅供参考。 首先,我们需要创建一个核心的容器类来管理Bean的生命周期和依赖注入。这个容器类需要实现BeanFactory接口,提供getBean()方法来获取Bean对象。 ```java public interface BeanFactory { Object getBean(String name); } ``` 接下来,我们需要实现一个简单的Bean定义类,用于描述Bean的属性和依赖关系。 ```java public class BeanDefinition { private Class<?> beanClass; private Map<String, Object> properties = new HashMap<>(); private List<PropertyValue> propertyValues = new ArrayList<>(); public void setBeanClass(Class<?> beanClass) { this.beanClass = beanClass; } public Class<?> getBeanClass() { return beanClass; } public void addProperty(String name, Object value) { properties.put(name, value); } public Object getProperty(String name) { return properties.get(name); } public List<PropertyValue> getPropertyValues() { return propertyValues; } public void addPropertyValue(PropertyValue propertyValue) { propertyValues.add(propertyValue); } } public class PropertyValue { private final String name; private final Object value; public PropertyValue(String name, Object value) { this.name = name; this.value = value; } public String getName() { return name; } public Object getValue() { return value; } } ``` 然后,我们需要实现一个简单的BeanFactory实现类,用于创建和管理Bean对象。这个实现类需要读取Bean定义信息,创建Bean实例,并将其保存在一个Map中。 ```java public class SimpleBeanFactory implements BeanFactory { private final Map<String, BeanDefinition> beanDefinitions = new HashMap<>(); private final Map<String, Object> beans = new HashMap<>(); public SimpleBeanFactory(String configLocation) { loadBeanDefinitions(configLocation); createBeans(); } private void loadBeanDefinitions(String configLocation) { // 从配置文件中读取Bean定义信息 } private void createBeans() { for (String beanName : beanDefinitions.keySet()) { createBean(beanName); } } private Object createBean(String beanName) { BeanDefinition beanDefinition = beanDefinitions.get(beanName); Class<?> beanClass = beanDefinition.getBeanClass(); Object bean = createInstance(beanClass); applyPropertyValues(bean, beanDefinition.getPropertyValues()); beans.put(beanName, bean); return bean; } private Object createInstance(Class<?> beanClass) { try { return beanClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } private void applyPropertyValues(Object bean, List<PropertyValue> propertyValues) { for (PropertyValue propertyValue : propertyValues) { String propertyName = propertyValue.getName(); Object value = propertyValue.getValue(); setPropertyValue(bean, propertyName, value); } } private void setPropertyValue(Object bean, String propertyName, Object value) { try { BeanUtils.setProperty(bean, propertyName, value); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } @Override public Object getBean(String name) { return beans.get(name); } } ``` 最后,我们需要实现一个简单的测试类来验证我们的实现是否正确。 ```java public class SimpleBeanFactoryTest { @Test public void testGetBean() { BeanFactory beanFactory = new SimpleBeanFactory("classpath:beans.xml"); TestBean testBean = (TestBean) beanFactory.getBean("testBean"); assertNotNull(testBean); assertNotNull(testBean.getDependency()); } } ``` 这只是一个简单的Spring源码实现示例,实际上Spring的源码实现要复杂得多,涉及到很多高级特性和设计模式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值