美文网首页React Native开发经验集ReactNativeReact Native开发
一起学react(2) dva底层源码与案例分析

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

作者: fangkyi03 | 来源:发表于2018-03-27 20:50 被阅读1726次

    本次主要针对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 告知一下 多谢!!

    相关文章

      网友评论

      • woo12345:那些带下划线同名方法是做什么的,缓存值,后续使用吗?
      • woo12345:厉害了
      • 薛墨林:追过来再看看

      本文标题:一起学react(2) dva底层源码与案例分析

      本文链接:https://www.haomeiwen.com/subject/snuscftx.html