大白话讲讲 React 中Fragments的作用,在避免额外 DOM 节点时如何使用它

132 阅读8分钟

作为一名前端工程师,日常工作中没少和React打交道,面试时也总逃不过被问到各种React相关的问题。其中,“React 中Fragments的作用是什么?在避免额外 DOM 节点时如何使用它?”这道题,可是出现频率相当高的“常客” 。今天咱就用大白话唠唠,帮大家彻底搞明白,不仅能轻松应对面试,还能在实际开发中把Fragments用得明明白白,顺便缓解缓解咱工作和家庭的压力,毕竟技术学扎实了,工作顺了,心情自然就好了!

被多余DOM节点支配的“恐惧”

在React开发里,组件返回内容时,常常会遇到一个让人头疼的问题。就拿写一个简单的列表组件来说,需求是展示一个水果列表,代码可能会像下面这样写:

import React from'react';

const FruitList = () => {
  return (
    <div>
      <li>苹果</li>
      <li>香蕉</li>
      <li>橘子</li>
    </div>
  );
};

export default FruitList;

这样看起来好像没啥问题,页面上也能正常展示出水果列表。但如果我们的组件结构稍微复杂一些,比如要做一个页面,里面有多个小组件,每个小组件都需要返回多个元素,这时候问题就来了。假设我们有一个 Article 组件,里面要展示文章标题、作者和内容:

import React from'react';

const Article = () => {
  return (
    // 报错!不能返回多个根节点
    <h1>文章标题</h1>
    <p>作者:张三</p>
    <p>文章内容:这是一篇精彩的文章...</p>
  );
};

export default Article;

React会报错,因为 一个组件必须有且只有一个根节点 。这时候,很多人第一反应就是再套一个 <div> ,把这些元素包起来,就像这样:

import React from'react';

const Article = () => {
  return (
    <div>
      <h1>文章标题</h1>
      <p>作者:张三</p>
      <p>文章内容:这是一篇精彩的文章...</p>
    </div>
  );
};

export default Article;

虽然问题解决了,组件能正常渲染了,但是从HTML结构角度来看,这个额外的 <div> 其实是多余的,它没有任何实际的语义,还会让DOM结构变得臃肿,增加不必要的层级,影响性能和后续的样式编写、DOM操作等工作 。这种被多余DOM节点支配的“恐惧”,相信不少前端小伙伴都深有体会!

Fragments——React的“隐形包裹器”

为了解决这个问题,React引入了Fragments(片段)。简单来说,Fragments就像是一个 隐形的包裹器 ,它可以把多个元素包裹起来,让组件有一个“虚拟”的根节点,这样就能满足React组件必须有一个根节点的要求,同时又不会在实际的DOM结构中生成多余的节点 。

Fragments有两种语法形式: 显式语法短语法 。显式语法使用 <React.Fragment> 标签,而短语法则使用更简洁的 <> 标签。它们的作用是一样的,只是写法不同,就好比穿衣服,有人喜欢宽松的款式,有人喜欢修身的款式,目的都是保暖,只是风格不同。

从原理上讲,当React在渲染组件时,遇到Fragments,它会把Fragments包裹的所有子元素直接添加到父节点下,而不会创建一个新的DOM元素。这就好比搬家时,把多个小物件直接放进一个大箱子里,到了新家,直接把小物件拿出来摆放,大箱子就“消失”了,不会占用额外的空间。

代码示例:手把手教你用Fragments

显式语法示例

import React from'react';

const Article = () => {
  return (
    // 使用显式语法的Fragments
    <React.Fragment>
      <h1>文章标题</h1>
      <p>作者:张三</p>
      <p>文章内容:这是一篇精彩的文章...</p>
    </React.Fragment>
  );
};

export default Article;

在这段代码中,我们使用 <React.Fragment> 把文章的标题、作者和内容包裹起来,这样既满足了React组件返回一个根节点的要求,又不会在实际的DOM中生成多余的节点。

短语法示例

import React from'react';

const Article = () => {
  return (
    // 使用短语法的Fragments
    <>
      <h1>文章标题</h1>
      <p>作者:张三</p>
      <p>文章内容:这是一篇精彩的文章...</p>
    </>
  );
};

export default Article;

短语法更加简洁直观,用 <></> 替代了 <React.Fragment></React.Fragment> ,效果是一样的。在实际开发中,大多数情况下我们会优先使用短语法,因为写起来更省事。

在列表渲染中使用Fragments

假设我们要渲染一个包含序号的水果列表,代码如下:

import React from'react';

const FruitList = () => {
  const fruits = ['苹果', '香蕉', '橘子'];
  return (
    <ul>
      {fruits.map((fruit, index) => (
        // 使用Fragments包裹列表项和序号
        <>
          <span>{index + 1}.</span>
          <li>{fruit}</li>
        </>
      ))}
    </ul>
  );
};

export default FruitList;

在这个例子中,我们通过Fragments把序号和水果名称包裹起来,避免了为每个列表项额外添加一个 <div> 等多余节点,让DOM结构更加简洁。

对比效果:有Fragments和没有Fragments的区别

下面通过一个表格来对比一下使用Fragments和不使用Fragments时的DOM结构和代码情况:

情况代码示例生成的DOM结构优点缺点
不使用Fragments,用额外<div>包裹jsx return <div><h1>标题</h1><p>内容</p></div>; <div><h1>标题</h1><p>内容</p></div>满足React组件根节点要求产生多余DOM节点,结构臃肿,影响性能和样式编写
使用显式语法Fragmentsjsx return <React.Fragment><h1>标题</h1><p>内容</p></React.Fragment>; <h1>标题</h1><p>内容</p>避免多余DOM节点,结构简洁,提升性能语法相对冗长
使用短语法Fragmentsjsx return <><h1>标题</h1><p>内容</p></>; <h1>标题</h1><p>内容</p>避免多余DOM节点,结构简洁,提升性能,语法简洁不支持 key 属性(某些特殊场景有局限性)

从表格中可以明显看出,使用Fragments相比使用额外的 <div> ,在DOM结构和代码简洁性上都有很大的优势,尤其是在复杂组件结构中,这种优势会更加明显。

面试大白话回答方法

面试官问起“React 中Fragments的作用是什么?在避免额外 DOM 节点时如何使用它?”,咱可以这样回答:

“面试官您好!React 中Fragments就像是一个隐形的小袋子,专门用来解决组件返回多个元素时的问题。因为React规定一个组件必须有且只有一个根节点,以前遇到要返回多个元素的情况,我们只能套一个 <div> 把它们包起来,但这样会在实际的DOM结构里多出一个没用的节点,很麻烦。

Fragments就不一样了,它能把多个元素包起来,让组件有一个虚拟的根节点,满足React的要求,而且在最终生成的DOM里不会留下任何痕迹,DOM结构能保持简洁干净,对性能和后续开发都有好处。

它有两种写法,一种是显式语法 <React.Fragment> ,一种是短语法 <> 。显式语法写起来稍微长一点,但是很规范;短语法更简洁,用得最多。比如我要返回文章的标题、作者和内容,就可以用 <> 把它们包起来,像这样 <><h1>标题</h1><p>作者</p><p>内容</p></> ,简单又实用!”

这样回答,既通俗易懂,又把重点说清楚了,面试官一听就知道你对Fragments理解得很到位!

Fragments——提升React开发效率的“利器”

通过上面的讲解,相信大家对React中的Fragments已经有了深入的了解。Fragments主要有两个核心作用: 解决组件返回多个元素的问题避免生成多余的DOM节点 。它的两种语法形式各有特点,在实际开发中可以根据具体情况灵活选择使用。

掌握Fragments的使用,不仅能让我们在面试中脱颖而出,更重要的是能在项目开发中写出更简洁、高效的代码,减少不必要的麻烦,提升开发效率。下次再遇到需要返回多个元素的场景,可别忘了用Fragments这个“利器”哦!

扩展思考

  1. Fragments和普通容器元素的性能差异有多大? 在简单场景下,两者的性能差异可能不太明显。但在大型项目中,大量使用多余的DOM节点会增加浏览器解析和渲染的负担,而Fragments由于不会产生额外节点,性能优势就会逐渐显现出来。

  2. 短语法Fragments不支持key属性,那在哪些场景下会有影响? 当我们在列表渲染中,需要给Fragments包裹的元素添加唯一标识时,如果使用短语法,就无法直接添加 key 属性。这时候可以使用显式语法 <React.Fragment key={uniqueKey}> ,或者将 key 添加到Fragments包裹的子元素上。

  3. 除了避免多余DOM节点,Fragments还有其他用途吗? Fragments还可以用于在组件中分组相关元素,让代码结构更加清晰,比如在表单组件中,把多个输入框和标签用Fragments分组,便于管理和维护。

希望这篇文章能帮大家彻底搞懂React中Fragments的相关知识!如果在学习和使用过程中有任何问题,欢迎在评论区交流讨论,咱们一起进步,共同缓解前端人的“压力山大”!

中Fragments的相关知识。你对文章内容的风格、篇幅还有其他想法,或是想了解其他前端面试题,都能随时和我说。