网站首页 > 技术文章 正文
一、Fragment 的核心概念
Fragment
它不仅解决了 JSX 要求必须有一个单一父元素的限制,同时避免了因额外容器元素导致的性能损耗和 DOM 结构冗余。
1. 为什么需要 Fragment?
在 React 的 JSX 中规定,每个组件的返回值必须是一个单一的根元素。例如:
function App() {
return (
<div>
<h1>标题</h1>
#技术分享 #掘金
<p>内容</p>
</div>
); }
在这里,你必须使用 <div> 来包裹两个子元素,然而,你会发现,如果这样做,那么 DOM 中就会多出一个无意义的 <div> ,非常影响样式和性能。
而使用 Fragment 刚好可以完美解决这个问题。
二、Fragment 的核心特性
1. 避免冗余 DOM 结构
Fragment 允许直接返回多个元素,而无需添加额外的容器节点。
示例:使用 Fragment 替代 <div>
function App() {
return (
<Fragment>
<h1>标题</h1>
<p>内容</p>
</Fragment>
); }
对比:
- 使用 <div> :
- 使用 Fragment:
分析: 传统的 <div> 会生成额外的 DOM 节点,导致不必要的层级嵌套,Fragment 通过虚拟 DOM 机制,直接将子元素插入目标位置,避免生成真实 DOM 节点。
2. 提升性能
Fragment 的底层就是基于 文档碎片(DocumentFragment)的,它可以通过批量操作 DOM 来减少重排重绘的次数。
示例:
<script>
const fragment = document.createDocumentFragment(); const title = document.createElement('h1'); const content = document.createElement('p'); fragment.appendChild(title); fragment.appendChild(content); document.body.appendChild(fragment); </script>
分析:
- 如果按照传统方法,那么逐个插入 DOM 元素(如使用 appendChild(wrapper) ),一定会导致页面的多次重排重绘,这样非常消耗性能。
- 而通过上面的代码,我们先将所有元素添加到文档碎片中,再一次性插入 DOM,这样减少浏览器的渲染压力,比如:
- document.createDocumentFragment() :这里我们创建了一个虚拟 DOM 容器 DocumentFragment ,用来临时存储多个 DOM 元素。
- 而且,这个节点非常特殊,它 不会被插入到实际的 DOM 树中 ,并且可以像普通 DOM 节点一样操作(如添加子元素)。
- 因此,它也 不会触发浏览器的重排(Reflow)和重绘(Repaint) 操作。
- 最终,在将其他子标签添加到这个容器后,它就将 DocumentFragment 中的所有子元素一次性插入到 <body> 中。
3. 支持 key 属性
在列表渲染中,Fragment 必须配合 key 属性使用,以避免 React 警告。
示例:列表中的Fragment
const items = [
{ id: 1, title: '标题1', content: '内容1' },
{ id: 2, title: '标题2', content: '内容2' }
];
function Demo({ items }) { return items.map(item => ( <Fragment key={item.id}>
<h1>{item.title}</h1>
<p>{item.content}</p>
</Fragment>
)); }
分析:
React 要求列表中的每个元素必须有唯一 key ,否则会抛出警告,因为 Fragment 添加 key 之后,才能确保 React 能正确识别每个子元素组,并且 key 只能用在 Fragment 的顶层,不能嵌套使用。
四、Fragment 的实现原理
1. 语法糖 vs 显式导入
- 语法糖 : <Fragment></Fragment> 可以简写为 <></> ,这也是我们创建一个React项目后App.jsx中常见的标签。
- 显式导入 :如果需要像上面讲得一样使用 Fragment 标签,那么你要先从 react 中导入 Fragment 组件才能使用。
import { Fragment } from 'react';
到这里你可能会想,既然能简写成 <></> ,我为什么还要使用更复杂的 Fragment 。
那么这里就要看使用场景了。
<></> 更简洁,适合简单的场景,而显式导入 Fragment 则可以指定 key 或添加注释,所以我们一般优先使用 <></> ,只有在需要显式配置时才用 Fragment 。
2. 虚拟 DOM 的优化
上面说过,React 的虚拟 DOM 会将 Fragment 的子元素直接插入到真实 DOM 中,不会创建实际的节点。例如:
<>
<h1>标题</h1>
<p>内容</p>
</>
实际上,它会被转换为:
React.createElement(React.Fragment, null,
React.createElement('h1', null, '标题'),
React.createElement('p', null, '内容')
);
分析: React 会通过虚拟 DOM 对比差异,把 Fragment 的子元素直接插入目标位置,来避免生成额外的 DOM 节点,减少内存占用和渲染时间。
五、总结
1. Fragment 的核心优势
- 简化 DOM 结构 :避免不必要的容器节点。
- 提升性能 :减少 DOM 操作次数,优化重排重绘。
- 灵活渲染 :支持多元素返回和条件渲染。
2. 最佳实践
- 优先使用 Fragment :在需要返回多个元素时,优先选择 Fragment。
- 列表渲染中使用 key :确保每个 Fragment 有唯一的标识。
- 避免嵌套 Fragment :过度嵌套可能导致可读性下降。
- 上一篇: 浅谈JavaScript中Blob对象
- 下一篇: 前端录屏黑科技:几行 JS 代码就能实现!
猜你喜欢
- 2025-08-03 一起学 pixijs(4):如何绘制文字
- 2025-08-03 csdn免录可复制实现当前页面生成二维码链接
- 2025-08-03 前端分享-少年了解过iframe么
- 2025-08-03 收好这个提示词!让DeepSeek帮我们生成精美网页表格!
- 2025-08-03 前端录屏黑科技:几行 JS 代码就能实现!
- 2025-08-03 浅谈JavaScript中Blob对象
- 2025-08-03 救命!这10个Vue3技巧藏太深了!性能翻倍+摸鱼神器全揭秘
- 2025-08-03 浏览器点击链接打开指定APP是如何实现的?
- 2025-08-03 数组长度检查竟然这么慢!用这行代码解决
- 2025-05-15 网页中如何实现点击按钮将文本复制到剪贴板?
- 08-05Advocate of ethical and safe use of AI that benefits all, not just a privileged few
- 08-05KKR Nears Completion of Dayao Soda Buyout in Rare Foreign Takeover of Chinese Beverage Brand
- 08-05The Rise of China’s Machine Tool Industry Despite the West's Export Restrictions
- 08-05Tesla Logs Largest Revenue Decline in Over A Decade as Q2 EV Sales Continues to Plunge
- 08-05Chinese vice premier calls for championing humanity's common values, promoting multipolar world
- 08-05China Unveils 600 km/h Superconducting Maglev Train, Expected to Slash Beijing–Shanghai Travel Time to 2.5 Hours
- 08-05Partnership can once again prove its mettle
- 08-05Amundi sees "US Exceptionalism" eroding, while turns bullish on China's AI
- 1521℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 640℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 527℃MySQL service启动脚本浅析(r12笔记第59天)
- 492℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 492℃启用MySQL查询缓存(mysql8.0查询缓存)
- 479℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 461℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 459℃MySQL server PID file could not be found!失败
- 最近发表
-
- Advocate of ethical and safe use of AI that benefits all, not just a privileged few
- KKR Nears Completion of Dayao Soda Buyout in Rare Foreign Takeover of Chinese Beverage Brand
- The Rise of China’s Machine Tool Industry Despite the West's Export Restrictions
- Tesla Logs Largest Revenue Decline in Over A Decade as Q2 EV Sales Continues to Plunge
- Chinese vice premier calls for championing humanity's common values, promoting multipolar world
- China Unveils 600 km/h Superconducting Maglev Train, Expected to Slash Beijing–Shanghai Travel Time to 2.5 Hours
- Partnership can once again prove its mettle
- Amundi sees "US Exceptionalism" eroding, while turns bullish on China's AI
- China's listed banks attract record investor visits on dividend appeal
- Huawei Denies Plagiarism in Pangu AI Model After Allegations of Copying Alibaba's Qwen
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- windowsscripthost (69)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)