一起学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# 安装脚手架


项目初始化部分

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

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

这里主要是看几点

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之前调用的会 走的是这个

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

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

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

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

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

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

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

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

但是可以提前了解一下

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

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

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

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

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

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

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

主要看看这个routes部分

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

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

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

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

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

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

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

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

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

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

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

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

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

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部分:

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

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

核心部分代码

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

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

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

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

4.

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

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

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

6.14

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

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

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

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

8. 

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

9.

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

10.

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

11.

dva-core中代码

dva中代码

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

12

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

13.

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

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

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

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

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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容