阅读时间大约5-10min~
前言
function App() {
return (
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
);
}
请问以上代码有什么问题,会报什么错? 答案:JSX元素必须被一个可闭合标签包裹⬇️
相信不少同学刚开始学习react的时候都编写过类似的代码,但大家有想过为什么会报这样的错吗?以及这样设计的目的是什么?
不了解也没有关系,接下来让我们一起逐步解密~
React.createElement与JSX
所有的JSX组件最终都通过React.createElement转化成对象交给react消费。
基本用法
React.createElement 接受至少三个参数:
- type: 字符串(代表 HTML 标签)或 React 组件(函数组件或类组件)。
- props: 对象,包含了该元素的属性。传递给元素的属性在组件中可通过 this.props 或 props 访问。
- ...children: 其余参数都会作为子节点(children)处理。这可以是更多的元素,字符串,数字等。
概念
当React在处理渲染一个组件的时候,它需要每个组件返回一个单一的根节点。JSX就是React.createElement的语法糖,每个JSX元素最终都会转化为React.createElement调用。例如⬇️
const element = (
<div>
<h1>Hello CodeSandbox</h1>
<h2 className='title'>Start editing to see some magic happen!</h2>
</div>
)
// 上述JSX最终会转化为⬇️
const element = React.createElement(
'div',
null,
React.createElement('h1', null, 'Hello CodeSandbox'),
React.createElement('h2', { className='title' }, 'Start editing to see some magic happen!')
)
综上所述,前言中的报错是因为React.createElement设计时是以单节点为基础的,所以同时传入多个节点会发生报错。 我们不妨再思考一下以下两个问题:
- 为什么设计React.createElement时是以单节点为基础的?
- 为什么传入<></>这样的空标签就不报错了呢?它最终其实也没有构建出真实的dom节点,这不是违背了React.createElement的设计初衷吗?。
React的单节点思想
接下来我想请大家跟我一起设想一个场景⬇️
首先,请大家抛弃react语法,用原生JS去思考这个问题。
现在有一个列表页,存在着3条数据,我点击了搜索,发现当前页面新增了4条数据,总共7条数据,这个时候你作为开发者,该怎么去更新dom呢?
这个时候你可能脱口而出,将这4条数据一条条塞进去,但大家应该都明白,每次操作dom的性能开销是很大的,需要进行dom插入(进行dom树的搜索),且会引起页面的回流重绘。如果进行多次操作,性能开销就会成倍增长。
现在你应该想到了,那我一次性把这4条数据的dom都塞进去,不就操作一次dom了吗?首先恭喜你回答正确,但可以再思考一下,我们怎么做到将4个dom一次性插入呢?原生js可没有类似的api支持你做到这一点,所以我们是不是需要将这多个dom合并成一个单一节点?这就是React的单节点思想。
<></>的原理
大家请先看上面这张图,我用了空标签包裹住了两个子标签,实现了react的单节点思想,但空标签却没有构建出真实的dom出来,他的原理是什么呢?
<></>的前世今生
如果你使用过react16.2之前的版本,你一定对React.Fragment这个词不陌生,因为在16.2版本之前,<React.Fragment></React.Fragment>充当了<></>的作用。所以<></>只是之前的语法糖。 至于为什么<></>没有构建出真实dom,这是因为react内部对Fragment做了特殊处理,将此作为一个抽象组件。
为什么要出现<></>
我认为有以下原因:
- 性能消耗:避免影响dom结构,如果每一个标签都强制用真实标签包裹,我们的dom树会多出不少冗余dom,结构会更加复杂,对后续的dom操作消耗会更大。
- 结构统一:虽然在真实dom中,<></>没有作用。但在React内部,它会被作为一个真实节点,react会将每一个节点存储并定位,以便于后续做diff以及更新操作。
总结
在结束之际,我想留给大家一个文中并没有解答的问题。
如果让你实现一个<></>,你会怎么去设计与实现呢?