这篇文章是从源代码的角度剖析react hooks,开始之前,对于react hooks的重要性以及为什么需要用函数组件可以参考React Hooks,彻底颠覆React,它的未来应该是这样的10 分钟快速入门:React Hooks
首先我们需要找到源代码,不少萌新小伙伴可能会从node_modules中的react模块包中去找hooks的源代码,如下图。(另注:因图片很多,会用图片编号来解读)
你所看到的只有这些hooks的定义,而其值的实现方式都是以var dispatcher = resolveDispatcher();再由这个dispatcher去调用对应的不同的事件,对于resolveDispatcher()方法的实现也会看得一头雾水,ReactCurrentDispatcher在这个源代码中啥都没有。所以从node_modules中react模块包解读hooks是行不通的。
我们需要把目标投向最原始的地方。react源码地址 请下载这个github的整个react代码仓库才能进行解读。
下载好了之后我们可以看到packages有32个模块包,接下来的讲解都在packages路径下,跟hooks强相关的react,react-reconciler两个模块包。
上面的图可以看到这是真正意义上的专门的定义reacthooks的本源,再继续寻找ReactCurrentDispatcher我们可以看到是引入了一个类型Dispatcher(派发者)
暴露出的Dispatcher方法里面的如useState,useEffect我们经常使用的只是类型定义,我自己在研究的时候查看上下文以及对应的引用发现不了更多有用的信息。
源代码研究不下去的时候应该换个角度,既然是只是定义类型,那一定有其他地方也会调用该类型从而获取hooks的更深层的实现。所以这里用了一个取巧的方式。
可以看到两个文件引用了ReactInternalTypes中定义的Dispatcher打开ReactFiberHooks.old.js之后就可以发现新大陆。
这里可以看到引入类Dispatcher的实现有三个对象HooksDispatcherOnMount(hooks派发在组件加载时),HooksDispatcherOnUpdate(hooks派发在组件更新时),HooksDispatcherOnRerender(hooks派发在组件渲染。这三个对象都是集中在renderWithHooks的函数之中(图不贴,请读者自行寻找),
本着追本溯源的方式我们找寻renderWithHooks的引用文件。在ReactFiberBeginWork.old.js中都使用在了updateFunctionComponent函数中,而这个函数是调用在了case FunctionComponent中,而代码下方的case ClassComponent所调用的方法的的updateClassComponent,所以
由于找到代码是采用的取巧的方式,再回过头总结下hooks的实现为一个词--分片任务调度。 对于分片这个词感到陌生的小伙伴可以拜读下这篇文章React源码剖析——(四)新引擎React Fiber
这篇文章中有提到两个阶段,Reconcile 阶段和Commit 阶段从这两个阶段分别对应ReactFiberBeginWork.old.js和ReactFiberCommitWork.old.js(现在文件中old和new代码都一样,可能facebook官方要做优化重构所以复制一份出来用old,new作为区分),
一、在reconcile阶段当解析到为函数组件时会调用核心方法renderWithHooks:
此方法会根据当前的分片任务中的current属性是否有任务去判断执行HooksDispatcherOnMount还是HooksDispatcherOnUpdate,在渲染阶段react调度器会适时得执行HooksDispatcherOnRerender
二、在commit阶段当解析到为函数组件时会对hook执行队列解除:
对于commitHookEffectListUnmount字面意思为解除提交过的hooks执行队列,将当前的一个个执行的hooksEffect置空或者销毁。
这篇文章篇幅有限,只对hooks怎么通过react的调度机制运行以及如何找寻hooks的源码进行解读,可能只是蜻蜓点水,还不够深入,整体运行的机制还需要各位看官自行再看源代码解读。
下一个篇幅将介绍hooks的那些方法源码的实现。