Preact 作为实现大部分 React 的接口,并且专注于轻量的框架,在前一阵 React 由于专利事件受到质疑的时候,进入了大家的视野,并且成为了在不得已需要放弃 React 之后的首选。虽然在今天,React 在 Twiter 上宣布其转向了 MIT 许可证,但也不影响我们对本框架设计的学习。本文作为 Preact 源码解读系列的第二篇,比较简短,将介绍 Preact 如何将 JSX 代码转义成 DOM 输出的流程
我们知道,在 React 中,对 JSX 代码的处理,是使用 React.React.createElement
来转换的,例如:
1 | import ReactDOM from 'react-dom' |
经过 Bable 转换后,得到的结果如下:
1 | var App = function App(props) { |
同样,在 Preact 中,对于 JSX 语法结构的处理,是使用 h
方法来处理的,比如:
1 | import { h, render, Component } from 'preact; |
使用 Babel 转换的结果为:
1 | var Index = function Index() { |
也就是使用 h
方法来处理。其中,h
方法的第一个参数是 nodeName
,代表元素的类型,第二个参数是元素的属性,第三个参数是元素中包裹的内容。同样,在调用 render
的时候,也是对生成的 Index
组件,调用 h
方法,我们可以看一下,h
函数内部到底做了什么:
其实 h
函数的代码并不多,所以可以先贴出来,然后慢慢分析流程
1 | const stack = []; |
其中,有几个注意点:
1 | if (simple && lastSimple) { |
做一个字符串拼接,是因为某些编译器会将下面代码
1 | let foo = <div id="foo">Hello World!</div>; |
转化为:
1 | var foo = h( |
最后将处理子节点的传入数组children中,现在传入children中的节点有三种类型: 纯字符串、代表dom节点的字符串以及代表组件的函数(或者是类)
还有:
我们可以看最后一个转化的例子:
1 | /* jsx |
最后,使用 render
方法将生成的 VNode 对象添加到 DOM 树中:
1 | render(<Index />, document.getElementById('container')) |
其中 render
的源代码为:
1 | export function render(vnode, parent, merge) { |
其实也是用的 diff
算法,至于 diff
算法的解析,可以参考我以前的文章 Preact 源码解析之 setState 相关流程