React 的最小实践 - Kut

2018-03-29 21:04:05 +08:00
 qiuyk

Kut

Kut,一个简单的 React-Like 的前端视图渲染库,是我在学习 React 源码时造的轮子。Kut 是基于 Typescript 的 React 最小实现。目前 Kut 支持的 Top-Level 方法仅有两个,即 createElement、render,同时也支持组件化开发,Demo 在这里

本文主要对 Kut 的源码进行说明和记录,项目地址:Github

源码说明

源码都在src目录下,目前一共 9 个文件,分别如下。

component.ts

定义了 Component 类,以用于自定义组件,只是定义了一些属性和方法,与 React 的 Component 类似。

element.ts

Element 是用于构造 Virtual DOM 节点的对象,element.ts 中包含一个工厂函数 createElement。Element 有 3 个属性:type 是类型,可以是 DOM tag (如 div 等)或自定义组件(即 Component 子类); key 用于 diff 时对节点进行唯一区分; children 是子节点数组,其元素可以是文本或者 Element,和 React 的区别是,如果 children 只有一项时,Kut 的 children 仍是数组,不过只有一项。

instance.ts

instance.ts 中包含了三种不同类型 Element 对应的实例类 Instance,对应 ReactComponent (注意区别 Component,为避免混淆,Kut 中命名为 Instance ),分别为文本实例 TextInstance、DOM 节点实例 DOMInstance 和自定义组件实例 ComponentInstance。三种 Instance 类结构基本类似,首先包含其对应于 DOM 节点的唯一 kutId,以方便进行挂载、更新和卸载;而 index 只用于列表项没指定 key 时使用,可忽略; key 和 node 用于获取 DOM 节点的 key 和节点本身。

Instance 的价值主要在于 mount、shouldReceive、update 和 unmount 方法。mount 方法用于遍历 VDOM 树,拼接 HTML 和添加监听函数。而 shouldReceive 用于判断是否为同一节点,若 Element 的 type 和 key 相同,则直接调用 update 更新,否则调用 unmount 卸载并重新 mount 挂载。update 方法则递归更新以当前节点为根节点的 VDOM 子树,其中若 children 大于一项的,会使用 diff 算法计算其差异并调用 patch 进行更新。最后,unmount 方法则从 DOM 树上卸载节点,并清除引用。

diff.ts

对于列表项更新,需要使用 diff 算法计算其差异。React 的实现可以参考这篇文章,我称其为前向 diff。Kut 基本的实现逻辑和 React 是相似的,但对于把元素从列表中底部挪到顶部的做法,React 的前向 diff 会导致 DOM 更新操作过多。Kut 的做法是引入后向 diff,逻辑是和前向 diff 一致,只是方向相反,时间复杂度仍为 O(n)。取前向 diff 和后向 diff 的更新操作较少者,调用 patch 函数对 DOM 进行更新。这部分解释我都写在了 diff.ts 的注释里了。

kut.ts renderer.ts constant.ts util.ts

分别是入口文件、渲染方法、一些常量和一些工具函数。其中 renderer.ts 中定义了 Element 实例化 instantiate 函数(即由 Element 生成 Instance )和 render 函数(使用 innerHTML 进行挂载),由于采用 innerHTML 方法进行挂载,需要使用事件委托来处理事件,也需要使用 DOM 节点唯一 kutId 进行区别,具体见 event.ts 。

event.ts

React 为保证兼容性,具有合成事件。而 Kut 为简单起见,仍使用原生事件,采用事件委托的方式,将所有监听函数挂在 document 上。event.ts 的做法参考了的做法,实现了在 document 上添加和删除监听函数的方法,并以 kutId 判断触发的节点。

后续计划

最近忙着实习面试和论文暂时也没太多时间加新功能,现在仍然有些 bug,如 componentDidMount 的触发时机不对。慢慢先打算支持异步更新和 Context,起码让 Redux 能用对吧,先写篇记录免得后头来看连自己都忘了(苦笑)。推荐个最近看到的关于 React 源码的专栏,感觉讲得还不错的,在这里:编程小思

欢迎 pr 和 stars,项目地址:Github

2449 次点击
所在节点    JavaScript
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/442631

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX