dva源码解析

本文详细解析了dva框架的源码结构,包括dva与dva-core两个部分的功能。dva对外提供了配置处理和应用启动,dva-core负责核心功能如创建对象、初始化模型、中间件处理等。在启动过程中,进行了数据校验、调用dva-core的start方法、配置Provider及渲染React组件。同时,深入探讨了dva如何注册和管理model,以及start方法中的createPromiseMiddleware、getSaga方法实现异步处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 dva的源码结构

dva的源码分为dva,和dva-core两个部分,dva/src下的文件负责处理对外的逻辑,包括数据校验,app对象封装,配置用户传入的路由等参数,并在最后启动了一个react应用。
dva-core的部分是dva核心功能实现部分,通过create方法返回一个dva对象给dva/src。使用内部的start方法初始化各种被dva/src配置过的属性。

二 dva/src/index.js

1. export的函数的功能

export的函数返回了一个app对象,这个对象挂载了dva所有的属性和方法,其中start方法是应用启动方法。

2. 初始化配置

在导出函数开始,根据用户传入的配置初始化默认的dva配置,包括默认的HashHistory,react-router-redux提供的routerReducerrouterMiddleware(在dva-core里面整合reducer的时候有用到),定义setupApp方法,用于代理history属性到app上。

// history库提供,将HTML5 BOM提供的History API进行封装
const history = opts.history || createHashHistory();
const createOpts = {
   
  initialReducer: {
   
    routing,
  },
  
  setupMiddlewares(middlewares) {
   
    return [
      routerMiddleware(history),
      ...middlewares,
    ];
  },
  
  // 在dva-core/index: start方法中调用
  // patchHistroy(history)可以监听history变动,从而触发回调
  setupApp(app) {
   
    app._history = patchHistory(history);
  },
};

function patchHistory(history) {
   
  const oldListen = history.listen;
  history.listen = (callback) => {
   
    callback(history.location);
    return oldListen.call(history, callback);
  };
  return history;
}

3. start方法

(1)数据校验

start方法在内部校验了数据,主要有以下几个:

  • 1)检查传入的container参数,接受dom元素或者是字符串,用querySelector方法查找dom元素,并判断container是否是HTMLElement元素,依据是否存在nodeNamenodeType属性。
  • 2)检查是否在之前注册过router,并且要求router是一个函数
(2)调用dva-core的start方法

之后,dva/src下面的start方法调用了dva/core返回的对象的start方法,并且由于要提供用户配置的参数,将dva/src的app对象的this通过call方法传入。
在这个start方法中,dva初始化了store,reducer,model等等,将这些对象全部挂载到了dva/src传入的this下的app对象,也就是最终dva返回的对象。

(3)配置Provider

之所以我们使用dva,可以使用Providerconnect方法,而不需要在根组件上做配置,是因为,在这一步,dva已经集成了react-redux插件的provider组件。

// app是dva对象,history默认是用history库的createHashHistory生成的,
// 将BOM的History封装后的history对象。
const DvaRoot = extraProps => (
    <Provider store={
   store}>
      {
    router({
    app, history: app._history, ...extraProps }) }
    </Provider>
  );
(4)渲染react组件

Provider组件包裹后的JSX对象比传递给了react,用于渲染。

三 dva-core/index

1. create方法

create方法 是被默认导出的。create方法内部创造了一个app对象并挂载了_models,包含dvaModel和所有的用户model,_store默认为null,plugin属性挂载各种插件,这些插件是基于dva生命周期函数的,plugin.use方法被plugin对象代理,以免找错this,model方法用于注册model,start方法用于启动程序。最终create方法返回了这个app对象。

const app = {
   
    _models: [prefixNamespace({
    ...dvaModel })],
    _store: null,
    _plugin: plugin,
    use: plugin.use.bind(plugin),
    model,
    start,
};

2. plugin对象

在create方法中,首先创建了Plugin对象,并用filterHooks方法过滤掉不合法的插件。plugin对象负责管理和使用中间件。

// hooks是所有生命周期钩子函数的键名
const hooks = [];

// filterHooks函数过滤了所有的生命周期钩子
export function filterHooks(obj) {
   }

export default class Plugin {
   
  constructor() {
   
    // 将this.hooks初始化为一个对象,
  }
  // 中间件,即是使用plugin.use()方法注册
  use(plugin) {
   }
  // 全局错误处理函数
  apply(key, defaultHandler) {
   }
  // 获取生命周期处理函数
  get(key) {
   }
}

// 将某一个key对应的生命周期函数的回调函数数组组合起来,生成一个对象
function getExtraReducers(hook) {
   }

// 将用户定义的reducer经过每一个reducer中间件处理
function getOnReducer(hook) {
   }

在plugin对象中,一共做了这么几件事:

  • (1)定义一个hooks生命周期钩子函数数组,并按照这个数组,初始化一个hooks对象,每一个属性是一个生命周期函数,被初始化为一个数组,挂载用户注册的插件。实际上dva的中间件或者说插件就是在这里被使用。
const hooks = [ 
  'onError', 'onStateChange', 'onAction', 'onHmr', 'onReducer', 'onEffect', 
  'extraReducers', 'extraEnhancers', '_handleActions',
];
  • (2)在Plugin的构造函数中,使用reduce方法创建hooks对象
// 将this.hooks初始化为一个对象,
// 它包括上面hooks数组的所有元素作为属性名,每个值都是一个空数组
// 这个空数组用来存放用户注册的中间件
this.hooks = hooks.reduce((memo, key) => {
   
  memo[key] = [];
  return memo;
}, {
   });
  • (3)plugin.use()方法用来注册中间件,注册的过程只是将用户定义的函数push进对应的钩子的数组中。
use(plugin) {
   
  // 数据校验,要求plugin是一个纯对象
  const hooks =
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值