为什么你应该使用 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 节点数量)
相关推荐
白兰地空瓶5 小时前
你以为 Props 只是传参? 不,它是 React 组件设计的“灵魂系统”
react.js
程序员码歌6 小时前
短思考第261天,浪费时间的十个低效行为,看看你中了几个?
前端·ai编程
Swift社区6 小时前
React Navigation 生命周期完整心智模型
前端·react.js·前端框架
若梦plus6 小时前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花7 小时前
Python环境安装
前端
Light607 小时前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy7 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴7 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里7 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路7 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端