拜读Preact源码有感
jsx本质
JSX是一种嵌入式的类似XML的语法,它可以被转换成合法的JavaScript,转换的语义是依据不同的实现而定的。例如react有react的jsx语法和转换器babel-plugin-transform-react-jsx ,vue有vue的jsx语法和转换器babel-plugin-transform-vue-jsx,当然,这也意味你可以开发自己的jsx语法和转换器jsx
react本质
babel-plugin-transform-react-jsx
react通过babel-plugin-transform-react-jsx将jsx语法转换为可以被React.createElement识别的形式,即:
<div id="foo" name="bar">Hello!</div>
// 转换为
React.createElement('div', { id: 'foo', name : 'bar' }, 'Hello!');
也就是说,react的jsx只是React.createElement的语法糖而已,我们看起来在写jsx,实际上babel-plugin-transform-react-jsx已经将我们写的jsx语法转换了。
React.createElement
jsx语法被转换器转换后,变成可以被React.createElement
所识别的内容。React.createElement(component, props, ...children)
则将能识别的相应内容解析为虚拟DOM。
React.createElement('div', { id: 'foo', name : 'bar' }, 'Hello!');
// 转换为
{
$$typeof: Symbol(react.element),
key: null,
props: {id: "foo", name: "bar", children: "Hello!"},
ref: null,
type: "div",
_owner: {},
_store: {}
}
虚拟DOM的本质:(virtual-dom)
虚拟DOM从本质上将就是将复杂的DOM转化成轻量级的JavaScript对象,不同的渲染中却会生成同样的虚拟DOM对象,然后通过高效优化过的Diff算法,比较前后的虚拟DOM对象,以最小的变化去更新真实DOM。
{
$$typeof: Symbol(react.element),
key: null,
props: {id: "foo", name: "bar", children: "Hello!"},
ref: null,
type: "div",
_owner: {},
_store: {}
}
// Hello 变为 Hello react
{
$$typeof: Symbol(react.element),
key: null,
props: {id: "foo", name: "bar", children: "Hello react!"},
ref: null,
type: "div",
_owner: {},
_store: {}
}
对比对象我们可以看到,只有 props.children 发生了变化,利用高效的对比diff方法找到不同,并把不同的内容修改,进行一个真实dom上的映射改变。即:
<div id="foo" name="bar">Hello!</div>
// dom映射后
<div id="foo" name="bar">Hello react!</div>
结语
即react的核心思想就是利用jsx转换器,将jsx转换为React.createElement能理解的形式,然后React.createElement又将相应内容解析为虚拟DOM。不同的渲染中却会生成同样的虚拟DOM对象,然后通过高效优化过的Diff算法,比较前后的虚拟DOM对象,最后通过dom的相应方法以最小的变化去更新真实DOM。无外乎是:jsx组件到虚拟DOM的转化、以及虚拟DOM到真实DOM的映射。