1. jsx 语法
在 react 配合 jsx 语法使用,通过 babel 的转译将 jsx 转译为浏览器可识别的 dom 元素。
<div>
<p>test</p>
</div>
上述代码经过编译会编译成下述结构
React.createElement('div', null, React.createElement('p', null, 'test'));
可以看到 jsx 语法被 React.createElement 转译。 可以通过 bebel 在线编译: bebel 在线编译
2. 实现react.createElement
从上述代码中可以看到,createElement有三个参数
- type: 元素的类型
- props: 元素的属性
- children: 子元素集合
我们创建一个项目来测试mini-react,
export default function createElement(type, props, ...children) {
return {
type,
props,
children
}
}
这样就可已得到初步的结果,
<div className="container">
<p>我是一段文字</p>
<div>
<p>我是嵌套的文字</p>
</div>
{false && <div>我不应该展示出来</div>}
{true && <div>我应该展示出来</div>}
</div>
结果被编译成了下述结构
{
children: [
0:
children: ['我是一段文字']
props: null
type: "p"
1: {type: 'div', props: null, children: Array(1)}
2: false
3: {type: 'div', props: null, children: Array(1)}
],
props: {className: 'container'},
type: "div"
}
这块我们发现有几个问题
- 当子元素是文字时直接生成的是一段文本
- 当值为boolean值的时候直接为false
我们在原有的基础上稍加改动
export default function createElement(type, props, ...children) {
const handleChildren = [].concat(...children).reduce((result, child) => {
// 判断child是否为boolean型且不能为空
if (child !== false && child !== true && child !== null) {
// 判断child是否为文本节点
if (child instanceof Object) {
result.push(child);
} else {
// 如果child为文本节点,则重新调用createElement方法,将文本转化为text类型的对象
result.push(createElement('text', { textContent: child }));
}
}
return result;
}, []);
return {
type,
props,
children: handleChildren,
};
}
此时我们在看输出则已经恢复正常。
我们在使用react开发的时候,父节点可以通过props.children获取子节点的数据,所以我们需要在返回值上重新赋值给props
export default function createElement(type, props, ...children) {
...
...
return {
type,
props: {children: handleChildren, ...props},
children: handleChildren,
}
}
至此我们的createElement方法已经实现完成。下一节我们会实现render方法。