一起学react(2) dva底层源码与案例分析

本次主要针对antd-pro案例来进行分析

用到的技术栈: dva dva-core antd-admin

之前写的一篇dva入手教程 反响挺不错的 今天就来点了解一下dva的核心代码

本人QQ:469373256 如果有问题 可以加我QQ

antd-pro官网

你可以使用集成化的命令行工具 ant-design-pro-cli。


$npminstallant-design-pro-cli -g


$mkdirmy-project&&cdmy-project


$ pro new# 安装脚手架


项目初始化部分

一起学react(2) dva底层源码与案例分析_第1张图片

一步步的来进行讲解 先看一下 接下来的代码分析 将会按照编号的顺序一点点往下讲

#1:dva初始化部分 源码地址:dva/packages/dva at master · dvajs/dva · GitHub

一起学react(2) dva底层源码与案例分析_第2张图片

这里主要是看几点

1.首先history部分 如果你没有传进去history的话 会默认给你使用HashHistory

2.你原来所有传进去的参数 又会被转换成createOpts 这部分 现在还用不到 在之后会讲到

3.这里通过将构造好的createOpts传递给core以后 返回了一个app 但是这里要注意的是 刚才第一个页面的时候 用到的router跟start其实都是在这里进行定义的dva-core本质是没有返回这部分数据的

#2: model加载部分 源码地址:dva/index.js at master · dvajs/dva · GitHub

model部分的代码 都是在dva-core里面的

这里这个model有点小小的区别

如果你这个app.model是在app.start之前调用的会 走的是这个

一起学react(2) dva底层源码与案例分析_第3张图片

而如果你在app.start之后调用的话 会走这个 一般用在按需加载的视图上面

一起学react(2) dva底层源码与案例分析_第4张图片

先针对第一个model做一下分析 第一个model代码很少 第二个model部分会在start以后进行讲解

其中checkModel是用来判断是否已经加载过对应的model了

prefixNamespace 这个是帮你构建一下函数对应的名字 比如你的app.model.effect下面有个*getapp({payload},{select,put,call})

这样的函数名字 那么 通过这个prefixNamespace转换以后 就会变成app/getapp

帮你进行了一下转换 附上对应的源码

一起学react(2) dva底层源码与案例分析_第5张图片

#3 router加载部分 源码地址:dva/index.js at master · dvajs/dva · GitHub

一起学react(2) dva底层源码与案例分析_第6张图片

router部分是在执行了app.start以后才会被触发的 所以这里是看不到的

但是可以提前了解一下

一起学react(2) dva底层源码与案例分析_第7张图片

如果这里的app.start(container)有值的话 会直接调用render来进行渲染 这里就是将刚才的app._router传递了过去 记得 刚才这个是有判断的 这个app._router必须是一个function 否则是会有问题的 再来看看具体的传参

一起学react(2) dva底层源码与案例分析_第8张图片

这里其实就很明显了 刚才的那个app.start(container)这个变量其实会被react-dom进行使用 具体可以看react-dom的文章 这边不细说

来看看关键的getProvider 这里你可以发现 我们刚才用到的app._router被传递了进来 并且变成了Provider的children来实现

那么再进一步 去看看这个app._router究竟干了什么

这部分的代码比较多 先贴主要部分的

一起学react(2) dva底层源码与案例分析_第9张图片

这里可以看到我们刚才传递进来的这个app跟history这两个都非常重要 在后面会使用到

一起学react(2) dva底层源码与案例分析_第10张图片

这里单个的route就不说了 我想你们比我也清楚

主要看看这个routes部分

一起学react(2) dva底层源码与案例分析_第11张图片

从这里可以发现 除了path参数部分 其他的都被涵盖到了...dynamics这个里面 这是es6的语法 具体可以了解一下阮一峰的es6

有一点了解过route这个组件的话 其实会知道 这里是通过path去加载对应的组件的 并不是这边map了以后 就全部都被加载了

看一下react-router-dom 中switch部分的代码

一起学react(2) dva底层源码与案例分析_第12张图片

这里可以清楚的看到 如果匹配才会调用cloneElement返回视图 否则仅仅只返回一个null而已

继续往下说 我们现在假设我们的组件被符合调教 需要被加载了 那么我们的model又是什么时候被加载进去的呢 这里得深入的去看一下这个dynamic 这是一个高阶组件

一起学react(2) dva底层源码与案例分析_第13张图片

这里的设计非常巧妙得一步步的看下去

一起学react(2) dva底层源码与案例分析_第14张图片

1.这里对config传进来的参数做了一下重命名

2.如果你的config里面 有传进来resolve的话 默认就会调用你传进来的那个 这样你可以更加的自定义一点 如果没有的话 就返回默认的函数

3.判断model是否是有内容 如果没有返回一个空数组 并且直接调用resolveComponent返回对应要渲染的视图

4.判断model内容 如果不符合 就直接抛出去

5.如果内容符合的话 就遍历加载app.model进行加载 所以model是在这里被进行加载的

6.如果你想对LoadingComponent进行自定义的话 你就可以通过在config里面传参的方式

接下来看看关键的asyncComponent部分代码

一起学react(2) dva底层源码与案例分析_第15张图片

1.初始化loadComponent与asyncComponent 这里loadComponent是可以自己指定的 只要你的config里面有带上就可以自定义了 

2.开始加载load视图

3.首先在load这边进行resolve的时候 因为promise是一个异步也就是一个微任务的关系 所以有可能会出现在render之前运行 所以在之后对this.mounted进行了判断 如果已经到了didMount中的话 说明已经走了render 所以必须用setState来刷新 而反之 没有经过render的话 这里不需要用setState来刷新 只需要直接赋值就可以了 然后在render里面就可以获取到对应的最新数据了

ok router部分讲完了 接下来看start部分

#start部分 

dvacore源码地址:dva/index.js at master · dvajs/dva · GitHub

dva源码地址:dva/index.js at master · dvajs/dva · GitHub

这个start比较特殊 它其实有两个地方在执行 一个是dva 一个是dva-core

dva部分:

一起学react(2) dva底层源码与案例分析_第16张图片

这里主要看oldAppStart部分 这里调用的就是dva-core中的start

其他剩余的部分 在上面就已经讲了 就不多说了

核心部分代码

start部分代码比较多 而且比较杂 首先你要知道一件事情 就是dva是这么实现的 dva本质上有几个中间件router,saga,promise

dva并没有产生新的东西 而是基于redux对于中间件的分散方式的一种封装 使其能按照一定的规范去进行编写也就是model部分 ok 现在有了这个中间思想 在去看一下dva.core中start相关的代码

一起学react(2) dva底层源码与案例分析_第17张图片

1.初始化全局错误输出 在之后的所有getSaga里面 都会将这个onError作为参数带过去 以便获取到saga运行时的错误信息 并且会反馈到最外部的全局错误输出那边

一起学react(2) dva底层源码与案例分析_第18张图片

2.3 :创建saga与promise中间件 并且对getSaga进行初始化 这个在之后会用到

一起学react(2) dva底层源码与案例分析_第19张图片

4.

初始化一个saga变量 用于存放所有model中的effect副作用 在之后会用到

初始化外部提供的reducer在后面会进行合并 这里保留原生redux的功能 

将model中存在的reducer与saga进行合并

6.14

一起学react(2) dva底层源码与案例分析_第20张图片

可以看到 如果你的key是onReducer的话 会走到下面的getOnReducer 如果你对dva的option中 有设置onReducer这个字段的话 会将里面的所有内容执行一次返回最新的reducer

如果没有的话 就是有啥就返回啥了

一起学react(2) dva底层源码与案例分析_第21张图片

combineReducers这个没啥好说的 用过redux就知道这个是干啥的

7.createStore这里比较简单 一笔带过了

一起学react(2) dva底层源码与案例分析_第22张图片

8. 

一起学react(2) dva底层源码与案例分析_第23张图片

这两句代码会在之后的model中被用到 刚才有说过 如果start以后 还需要加载model的话 就需要这两个了

9.

一起学react(2) dva底层源码与案例分析_第24张图片

这里是用来全局监听state改变的地方 如果对redux熟悉的话 你的每次dispatch都是会触发回调的 所以这边会实时的传递最新得state

10.

还记得刚才将所有model的数据 放到一个数组的步骤吗 现在这里就可以直接拿来用了

11.

dva-core中代码

dva中代码

一起学react(2) dva底层源码与案例分析_第25张图片

这个代码的作用就是触发一个history的监听 至于history是什么 只要看一下初始化部分的代码就知道了

12

一起学react(2) dva底层源码与案例分析_第26张图片
一起学react(2) dva底层源码与案例分析_第27张图片

刚才setupApp开启了history的监听 那么这里就是把所有model的subscriptions跑一遍 可以看到sub那边传递过去的值 就是model里面能获取到的东西

13.

修改原有的model只想 使其指向一个新的地址 来看一下具体实现

一起学react(2) dva底层源码与案例分析_第28张图片

这里采取的方式是 如果是reducer部分 则采取直接使用redux自带的replaceReducer进行全部的替换 这里成本其实还是蛮大的

如果是effect部分的话 就获取对应的getSaga然后全部执行

subscriptions部分跟刚才说的那个一样不多讲了

一起学react(2) dva底层源码与案例分析_第29张图片
一起学react(2) dva底层源码与案例分析_第30张图片

简单来说就是 遍历所有的effect并且生成一个getWatcher通过fork的方式进行执行 通过这样的方式 所以你通过app/xxx的时候 才能直接获取到 因为这个会一直在运行 这里要注意是一直在运行 除非你使用了unmodel卸载了对应的model 也就是下面的一行代码

除非接收到了这个消息 否则会一直执行 这里其实还是比较占用内存的一个地方 看看卸载部分

一起学react(2) dva底层源码与案例分析_第31张图片

至此整个dva源码 分析完毕 如果有写的不对的地方 麻烦加我QQ:469373256 告知一下 多谢!!

你可能感兴趣的:(一起学react(2) dva底层源码与案例分析)