为什么你应该使用 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 节点数量)
相关推荐
拾光拾趣录17 分钟前
Element Plus表格表头动态刷新难题:零闪动更新方案
前端·vue.js·element
Adolf_19931 小时前
React 中 props 的最常用用法精选+useContext
前端·javascript·react.js
前端小趴菜051 小时前
react - 根据路由生成菜单
前端·javascript·react.js
喝拿铁写前端1 小时前
`reduce` 究竟要不要用?到底什么时候才“值得”用?
前端·javascript·面试
鱼樱前端1 小时前
2025前端SSR框架之十分钟快速上手Nuxt3搭建项目
前端·vue.js
極光未晚1 小时前
React Hooks 中的时空穿梭:模拟 ComponentDidMount 的奇妙冒险
前端·react.js·源码
Codebee1 小时前
OneCode 3.0 自治UI 弹出菜单组件功能介绍
前端·人工智能·开源
ui设计兰亭妙微1 小时前
# 信息架构如何决定搜索效率?
前端
1024小神2 小时前
Cocos游戏中UI跟随模型移动,例如人物头上的血条、昵称条等
前端·javascript
Mapmost2 小时前
告别多平台!Mapmost Studio将制图、发布、数据管理通通搞定!
前端