为什么你应该使用 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 节点数量)
相关推荐
光影少年2 小时前
angular生态及学习路线
前端·学习·angular.js
无尽夏_4 小时前
HTML5(前端基础)
前端·html·html5
Jagger_4 小时前
敏捷开发流程-精简版
前端·后端
FIN66684 小时前
昂瑞微冲刺科创板:创新驱动,引领射频芯片国产化新征程
前端·安全·前端框架·信息与通信·芯片
GISer_Jing4 小时前
ByteDance——jy真题
前端·javascript·面试
睡美人的小仙女1274 小时前
浏览器为何屏蔽本地文件路径?
前端
真的想不出名儿4 小时前
Vue 中 props 传递数据的坑
前端·javascript·vue.js
FIN66684 小时前
昂瑞微:深耕射频“芯”赛道以硬核实力冲刺科创板大门
前端·人工智能·科技·前端框架·信息与通信·智能
阳光阴郁大boy4 小时前
星座运势网站技术解析:从零打造现代化Web应用
前端·javascript
烛阴5 小时前
武装你的Python“工具箱”:盘点10个你必须熟练掌握的核心方法
前端·python