React Fragments——是什么、为什么、如何做
问题
解决方案
典型用例
我应该使用片段吗?
总结
React Fragments是在React 16.2.0中引入的。尽管它们已经存在一段时间了,但我交谈过的许多React开发人员还没有开始使用它们,而造成这种情况的首要原因通常是他们听说过它们,但还没有抽出时间去学习它们。
那么它们是什么?你该开始使用它们吗?后一个问题的答案是肯定的,而第一个问题的答案正是这篇博文将要告诉你的。
你是 React 新手吗?一定要阅读我的文章《每个 React 初学者都应该知道的 6 件事》。
问题
正如 React.js 文档所述,React 中常见的模式是组件返回多个元素。通常,这些元素会被包裹在一个例如 div 标签内。在大多数情况下,这个包裹元素是“无关紧要的”,添加它仅仅是因为 React 组件要求你只能返回一个元素。这种行为会导致无用的标记,有时甚至会渲染出无效的 HTML,这是不好的。
例如,我们可以创建一个名为 Table 的组件来渲染 HTML 表格,然后在表格内部使用另一个名为 Columns 的组件来渲染列。它看起来大概是这样的。
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Columns />
</tr>
</table>
);
}
}
class Columns extends React.Component {
render() {
return (
<div>
<td>Hello</td>
<td>World</td>
</div>
);
}
}
这将导致渲染出无效的 HTML,因为 Columns 组件中的包装 div 被渲染在<tr>.
<table>
<tr>
<div>
<td>Hello</td>
<td>World</td>
</div>
</tr>
</table>
解决方案
解决方案正如你所料,就是 Fragment!React Fragment 允许你将一系列子元素分组,而无需向 DOM 添加额外的节点,因为 Fragment 本身并不渲染到 DOM 中。所以,我们基本上用 React.Fragment 代替了通常会用到的 div 元素。
我们可以使用带有<React.Fragments>语法的片段。因此,我们可以按如下方式编写 Columns 组件。
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
现在表格组件将渲染以下HTML代码。
<table>
<tr>
<td>Hello</td>
<td>World</td>
</tr>
</table>
也可以使用类似空标签的简短语法来声明片段。以下是一个示例。
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
典型用例
返回多个元素
React Fragment 最常见的用途可能是在需要返回多个元素时。使用 Fragment 可以轻松实现这一点,而且无需像传统方式那样使用 div 来包裹元素。
class Application extends React.Component {
render() {
return (
<React.Fragment>
<Header />
<Content />
<Footer />
</React.Fragment>
);
}
}
条件渲染
React Fragment 也可用于条件渲染元素。它们可以简化元素组的渲染过程,而无需添加额外的标记。
class LoginForm extends React.Component {
render() {
return (
<form>
{this.props.isLoggedIn ? (
<React.Fragment>
<h3>Welcome</h3>
<p>You are logged in!</p>
</React.Fragment>
) : (
<React.Fragment>
<h3>Login</h3>
<label for="username">Username</label><br/>
<input type="text" id="username" /><br/>
<label for="password">Password</label><br/>
<input type="password" id="password" /><br/>
<input type="submit" value="Login" />
</React.Fragment>
)}
</form>
);
}
}
数组
在渲染数组时,片段也能帮上忙,因为片段可以拥有 key 属性!假设你有一个用户对象数组,想要渲染数组中的所有用户。你需要为每个用户设置 key 属性,所以通常需要使用类似 div 的元素来包裹用户信息。但是,由于片段可以拥有 key 属性,你可以直接使用片段并为其设置 key 属性,这样就无需添加任何额外的标记。
class UserList extends React.Component {
users = [
{
id: 1,
name: "Jack Bauer",
email: "jack.bauer@ctu.gov",
phone: "+358509283928"
},
{
id: 2,
name: "Tony Almeida",
email: "tony.almeida@ctu.gov",
phone: "+358508829378"
},
{
id: 3,
name: "Chloe O'brian",
email: "chloe.obrian@ctu.gov",
phone: "+358508899012"
}
];
render() {
return (
<React.Fragment>
{this.users.map(user => (
<React.Fragment key={user.id}>
<h2>{user.name}</h2>
<p>{user.email}</p>
<p>{user.phone}</p>
</React.Fragment>
))}
</React.Fragment>
);
}
}
我应该使用片段吗?
那么,使用片段(fragment)来代替例如包装 div 元素是否值得呢?
Dan Abramov在StackOverflow上回答了这个问题:
- 它速度略快,内存占用更少(无需创建额外的 DOM 节点)。这仅在非常大或非常深的树状结构中才真正有优势,但应用程序性能通常会因“千刀万剐”而下降。而这种方法减少了一次切割。
- 一些 CSS 机制,如 Flexbox 和 CSS Grid,具有特殊的父子关系,在中间添加 div 会使在提取逻辑组件时难以保持所需的布局。
- DOM 检查器界面更简洁了。🙂
因此,片段消除了可能导致无效 HTML 和组件样式问题的包装 div,再加上它们速度更快、DOM 更简洁,我认为它们值得使用。
总结
你对 React Fragment 有什么看法?你在自己的项目中使用过吗?请在下方留言,我很想听听你的想法!
别忘了订阅我的电子报,随时了解现代网页开发的最新资讯和文章。我还会为电子报订阅用户分享独家技巧和秘诀!点击此处订阅。
原文发表于tuomokankaanpaa.com,日期为 2019 年 10 月 6 日。
文章来源:https://dev.to/tumee/react-fragments-what-why-how-2kh1