React小知识(4) - dva源码之dynamic

1,448 阅读2分钟

使用过dva这款轻量框架的朋友应该对dynamic.js这个文件不陌生,他负责注册动态加载的model、渲染动态加载的component

先聊一下自己看代码最初没有理解的地方^_^,dynamic()入口方法:

这句代码咋看只是用了一个解构重命名的技巧,但是阅读起来就会产生疑惑。resolveModels 为什么要这么命名呢,好端端的 models 不好么。其实这涉及到了大家对传入dynamic 中的参数的理解。

因为传入的是一个promise的执行函数,因为执行后会得到一个 promise 的结果,所以起名为 resolveXXX

下面这段操作,开始我是一头雾水。

Promise.allret.slice(0, len), resolve(xxx) 拆开来都能看懂,为什么拼起来就看不明白了呢。

让我们逐步来分析一下

  • [...models, component] 是什么?

    答:动态加载 modelscomponentpromise

  • ret 是什么?

    答:所有 promise 执行完后的返回值组合而成的数组

  • 为什么要做 modelslength 判断?

    答:方便没有 models 时,直接 resolve(组件)

  • ret.slice(0, len) 是什么?

    答:所有 models 的返回结果组成的数组

  • resolve(XXX)到底 resolve 了什么?

    答:resolve 了一个组件

到此终于可以搞清楚这段代码的作用就是将加载 modelscomponentpromise 执行结果的数组中的 models 拿去注册,components resolve 到下个环节。

作为一个有求知欲的小伙伴(其实可能是个杠精),我对于源码的探索并没有止步,我发现了一个令我疑惑不解的事情this.mounted

  1. 为什么 this.load() 要在 contructor() 中执行,这个徒增了 this.mounted 变量,如果在 componentDidMount() 中去执行不应该更好么。

  2. 如果 this.state.AsyncComponent = AsyncComponent, 在 render 之后,在 componentDidMount 之前执行,会不会导致组件无法正常展示。

于是我请教了我们的垚哥哥,垚哥哥给出了非常让我信服的解释。

  1. 因为如果组件很快从 componentDidMount 状态变为 componentWillUnmount ,比如用户切换功能标签很快的场景,那么 resolve() 的异步操作仍会执行,会导致组件卸载后依然执行 this.setState 方法,导致内存泄露。
  2. render, componentDidMount 虽然是生命周期的两个方法,可以看作是同步执行(?,准确的说不是真正的同步,但是两个任务之间不会插入promise.then的执行,具体原理还得再研究)的,所以不存在this.state.AsyncComponent 会在两者执行之间的同时执行的问题。

通过对dva源码的学习,收获了一些不一样的知识,分享给大家。