React开发小点:组件为什么需要用标签包裹?return为什么加()?
前言
这次准备介绍关于react的两个新生开发过程中时不时会犯错或者不理解的两个小知识点:
1. React组件为什么需要用标签包裹?
2. React中return为什么加()?
React组件为什么需要用标签包裹?
看这样一段代码:
function App() {
return (
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
);
}
结果报错了
错误:JSX元素必须被一个可闭合标签
包裹
相信不少同学刚开始学习react的时候都编写过类似的代码,但大家有想过为什么会报这样的错吗?以及这样设计的目的是什么? 不了解也没有关系,接下来让我们一起逐步解密~
再此之前先来补充React.createElement
与JSX
的关系
React.createElement与JSX
JSX是React.createElement的语法糖
一段常见的jsx代码
// 部分jsx
<header className="App-header">
<h1>哈喽</h1>
</header>
jsx代码会被编译成React.createElement函数组成的js代码
在组件中,需要被渲染的内容是用React.createElement(component, props, ...children) 声明的,而 JSX 正是React.createElement函数的语法糖,JSX 会被编译为 React.createElement()
但浏览器本身不支持 JSX,所以在应用发布上线前,JSX 源码需要工具编译成由若干createElement函数组成的 JS 代码,然后才能在浏览器中正常执行。JSX 需要被编译,而编译这个动作就是由 Babel 来完成的。
经Babel编译成 JS 就会变成:
React.createElement("header", {className: "App-header"},
React.createElement("h1", null, "哈喽")
);
React.createElement的基本用法
React.createElement(component, props, ...children) 接受至少三个参数:
- type: 字符串(代表 HTML 标签)或 React 组件(函数组件或类组件)。
- props: 对象,包含了该元素的属性。传递给元素的属性在组件中可通过 this.props 或 props 访问。
- ...children: 其余参数都会作为子节点(children)处理。这可以是更多的元素,字符串,数字等。
单根节点思想
当React在处理渲染一个组件的时候,它需要每个组件返回一个单一的根节点。结合上述的代码,我们可以得到:
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时是以单节点为基础的?
接下来我想请大家跟我一起设想一个场景⬇️
首先,请大家抛弃react语法,用原生JS去思考这个问题。
现在有一个列表页,存在着3条数据,我点击了搜索,发现当前页面新增了4条数据,总共7条数据,这个时候你作为开发者,该怎么去更新dom呢?
这个时候你可能脱口而出,将这4条数据一条条塞进去,但大家应该都明白,每次操作dom的性能开销是很大的,需要进行dom插入(进行dom树的搜索) ,且会引起页面的回流重绘。如果进行多次操作,性能开销就会成倍增长。
现在你应该想到了,那我一次性把这4条数据的dom都塞进去,不就操作一次dom了吗?首先恭喜你回答正确,但可以再思考一下,我们怎么做到将4个dom一次性插入呢?原生js可没有类似的api支持你做到这一点,所以我们是不是需要将这多个dom合并成一个单一节点?这就是React的单节点思想。
所以我们之所以用标签包裹react组件的重要原因。
React组件中return为什么加()?
react有这么一个规则:
例如:
function Component() {
return
<div>{/*假设这行JSX语句很长*/}</div>;
}
放到编译器里会生成:
function Component() {
return;
React.createElement("div", null);
}
发现了没有
这都还没走到 React.createElement
就被return了
为了修正这个问题,我们需要为 JSX 加上括号:
function Component() {
return (
<div>{/*假设这行JSX语句很长,为了提升一些代码可读性,特地换行*/}</div>
);
}
再次编译:
function Component() {
return React.createElement("div", null);
}
这才是我们最终想要的效果了~
原因如下:
JavaScript会自动在每行的末尾添加分号,如果
return
语句后没有使用括号,就会在它的末尾自动插入一个分号(;)
,从而导致语法错误。通过使用括号,可以确保return
语句作为一个整体被正确解析,避免因为自动插入分号而导致的bug。