优秀的编程知识分享平台

网站首页 > 技术文章 正文

Fragment :从基本原理到深度解析

nanyue 2025-08-03 06:53:51 技术文章 5 ℃

一、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 :过度嵌套可能导致可读性下降。

最近发表
标签列表