为什么你应该使用 React Fragment 而不是 div?

React 中的 <></> Fragment:是什么及其原理详解

在 React 开发中,经常需要返回多个组件或元素,而 React 的 JSX 语法要求每个组件必须有一个根节点 。为了解决这个问题,React 提供了一个**Fragment(片段)**来解决这个问题。Fragment 的简写形式就是 <></>,它允许我们包裹多个子元素而不向 DOM 中添加额外的节点。

一、Fragment 是什么?

Fragment 是 React 提供的一个特殊的组件,用于包裹多个子元素,但它不会在最终的 DOM 中渲染出任何实际的节点。换句话说,它只是一个逻辑上的包裹结构,而不是一个真实的 DOM 元素。

在 JSX 中,Fragment 的写法有两种:

  • 显式写法:<React.Fragment>...</React.Fragment>
  • 简写形式:<></>

例如:

jsx 复制代码
return (
  <>
    <h1>标题</h1>
    <p>内容</p>
  </>
);

等价于:

jsx 复制代码
return (
  <React.Fragment>
    <h1>标题</h1>
    <p>内容</p>
  </React.Fragment>
);

二、为什么需要 Fragment?

在 React 中,每个组件的 render 函数或函数组件的返回值必须是一个单一的 React 元素。如果你尝试返回多个并列的元素,会报错

jsx 复制代码
// 错误示例
return (
  <h1>标题</h1>
  <p>内容</p>
);
jsx 复制代码
return (
	<div id='container'>
		<h1>标题</h1>
  	<p>内容</p>
	</div>
);

若使用 <div> 包裹多个元素会增加 DOM 树的深度,导致:

  • 页面结构变得复杂

  • 可能影响子元素的定位、布局

    使用flex、Grid布局时,父容器的直接子元素是布局的关键,如果插入了一个div,则会形成一个新的布局容器,从而打乱原有的布局。

  • 影响 CSS 选择器(如 :nth-child)的行为

而使用 Fragment 可以优雅地包裹多个元素,而不会引入多余的 DOM 节点。这对于保持 DOM 结构的整洁非常重要,尤其是在使用 CSS Flex、Grid 布局时,避免因多余的容器节点影响布局。

jsx 复制代码
return (
	<>
		<h1>标题</h1>
  		<p>内容</p>
	</>
);

三、Fragment 的特点

  • 不渲染 DOM 节点 , Fragment 只是一个逻辑结构,不会生成真实的 DOM

  • 支持 key 属性 ,如果你需要渲染一个列表中的 Fragment,可以为其指定 key

    jsx 复制代码
    import { Fragment } from "react";
    import "./App.css";
    
    function App() {
      const lists = [
        { id: 1, container: "内容1" },
        { id: 2, container: "内容2" },
        { id: 3, container: "内容3" },
      ];
      return lists.map((item) => (
        <Fragment key={item.id}>
          <h2>{item.container}</h2>
        </Fragment>
      ));
    }
  • 不支持 ref 和 style ,Fragment 不能绑定 ref 或设置 style,因为它不是一个真正的 DOM 元素

  • 可嵌套使用 Fragment 可以嵌套在其他 Fragment 或组件中

四、使用原生js实现与Fragment相同的效果

使用document.createDocumentFragment() 可以创建一个轻量级的文档片段(document fragment)。这个文档片段不属于主 DOM 树,但可以像标准 DOM 节点一样被操作。也就是说在最后的DOM树中不会有该节点的存在,其效果和Fragment一样。

以下的代码逻辑是使用document.createDocumentFragment()创建一个document fragment,然后一次性将多个节点添加到这个片段中,最后统一插入到DOM树中。document fragment 在这里充当一个临时的节点。

html 复制代码
    <div id="container"></div>
    <script>
      const lists = [
        {
          id: 1,
          title: '111',
          content: '111111',
        },
        {
          id: 2,
          title: '222',
          content: '222222',
        },
      ]

		
      // 创建document fragment 文档片段
      const fragment = document.createDocumentFragment()
      const container = document.getElementById("container");
		
        // 向文档片段插入节点
      lists.forEach((item) => {
        const div = document.createElement('div')
        const title = document.createElement('h2')
        const content = document.createElement('p')

        title.textContent = item.title
        content.textContent = item.content
        div.appendChild(title)
        div.appendChild(content)
        
        fragment.appendChild(div)
      });
      
      container.appendChild(fragment)
    </script>

效果如下

五、Fragment 的使用场景

  1. 返回多个并列元素

    jsx 复制代码
    function UserInfo() {
      return (
        <>
          <h2>用户名:Tom</h2>
          <p>年龄:25</p>
        </>
      );
    }
  2. 条件渲染包裹多个元素

    jsx 复制代码
    function Greeting({ isLoggedIn }) {
      return (
        <>
          {isLoggedIn ? <p>欢迎回来!</p> : <p>请登录</p>}
        </>
      );
    }
  3. 在列表中使用带有 key 的 Fragment

    jsx 复制代码
    function TodoList({ items }) {
      return (
        <ul>
          {items.map(item => (
            <React.Fragment key={item.id}>
              <li>{item.text}</li>
              <hr />
            </React.Fragment>
          ))}
        </ul>
      );
    }

六、Fragment 与 <div> 的区别

对比项 Fragment <div>
是否生成 DOM 节点 否 是
是否影响布局 否 是(可能破坏 CSS 布局)
是否影响语义 否 是(可能影响语义结构)
是否影响性能 否 是(增加 DOM 节点数量)
相关推荐
wangruofeng2 小时前
AI Models 1.1.0 发布,查大模型价格、对比模型和找 API 地址
前端·aigc·ai编程
wangruofeng2 小时前
给前端开发者的 100 个设计参考网站
前端·设计
星栈5 小时前
视频即代码,Remotion 能做什么、不能做什么
前端·音视频开发
广州华水科技5 小时前
单北斗GNSS位移监测系统的应用与技术解析
前端
用户47949283569156 小时前
从一句话或代码仓到可交互 HTML:开源 Agent 画图技能 Archify v3.2 实测与选型边界
前端·后端·面试
风骏时光牛马8 小时前
生成一个AI多模态标题,仅输出一条标题,无额外文字、问句、备选、配图、文案等任何附加内容,不需要其他的任务服务 只要标题。
前端
wangruofeng9 小时前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
清晨Coding10 小时前
为什么用 React Developer Tools 查看组件树这么乱?
前端·react.js
鶴哥只手遮天10 小时前
《Electron 45.2.3 内核解剖》第 4 章 补丁体系:380 个补丁改了什么
前端·electron
FungLeo12 小时前
成为全栈·Vue 管理后台篇·分类树与标签管理:层级数据如何落到管理界面
前端·javascript·vue.js·分类树·naive ui·标签管理·前端数据结构