为什么React 16中的片段比容器div更好?


165

在React 16.2中,增加了对的支持Fragments。可以在React的博客文章中找到更多信息

我们都熟悉以下代码:

render() {
  return (
    // Extraneous div element :(
    <div>
      Some text.
      <h2>A heading</h2>
      More text.
      <h2>Another heading</h2>
      Even more text.
    </div>
  );
}

是的,我们需要一个容器div,但这没什么大不了的。

在React 16.2中,我们可以这样做以避免周围的容器div:

render() {
  return (
    <Fragment>
      Some text.
      <h2>A heading</h2>
      More text.
      <h2>Another heading</h2>
      Even more text.
    </Fragment>
  );
}

无论哪种情况,我们仍然需要围绕内部元素的容器元素。

我的问题是,为什么使用Fragment首选?它对性能有帮助吗?如果是这样,为什么?希望有一些见识。


2
我发现在为父母创建一级孩子时,对于flexbox样式真的很有用
willwoo

32
问题div在于您并不总是需要包装元素。包装元素具有含义,通常您需要其他样式才能删除该含义。<Fragment>只是没有呈现的语法糖。在某些情况下,创建包装器非常困难,例如,在SVG中,<div>无法使用包装<group>并不一定总是您想要的包装。
苏珊(Sulthan),

Answers:


305
  1. 它快一点,并且内存使用量更少(无需创建额外的DOM节点)。这仅在非常大和/或较深的树上才有真正的好处,但是应用程序性能通常会遭受数千次削减的折磨。这少一分。
  2. 一些CSS机制(例如Flexbox和CSS Grid)具有特殊的父子关系,并且div在中间添加s使得在提取逻辑组件时难以保持所需的布局。
  3. DOM检查器比较整洁。:-)

您可以在此React问题中找到一些其他用例的描述:添加片段API以允许从render返回多个组件


24
4.编写定义列表<dt><dd>变得容易得多。返回配对元素之前很尴尬Fragments
Sonson123 '17

片段是否可以在本机中工作?我试着去import Fragment from 'react'。但是在RN中没有定义。
binchik

3
对于number 2,表格实际上是我们面临的最大问题。一些笨拙的React代码所需的结构table>tr>td(可能与之thead相似)。
Matsemann '17

2
@binchik试过了import {Fragment} from 'react'吗?这是一个命名的出口。
索斯卡

1
3号是最重要的!
扎克·史密斯

28

除了上述所有答案外,还有一个优点:代码可读性强Fragment组件支持语法糖形式,<>。因此,您问题中的代码可以更容易地编写为:

render() {
  return (
    <>
      Some text.
      <h2>A heading</h2>
      More text.
      <h2>Another heading</h2>
      Even more text.
    </>
  );
}

根据文档

在React中,这变成了<React.Fragment/>元素,如上一节中的示例所示。(使用JSX的非反应框架可能会编译成其他东西。)

整洁,对吗?

请注意,<Fragment>如果需要提供key给片段,您仍然需要使用语法。


create-react-app目前尚不支持这种较短的语法。请参阅:reactjs.org/docs/fragments.html#short-syntax
encodingsplash

2
@codingsplash CRA 2.0现在拥有它。
与Zaveri相遇

1
不能忍受这句语法糖,它看起来是无意的,几乎没有传达任何内在含义。更喜欢<Fragment>
ESR

3
@ESR我个人喜欢。这样想吧。孩子们什么也没包裹,就像<>中什么也没有。无形。
user3614030

6
  • JSX之前无法提供的新增功能
  • 更好的语义jsx标记。包装器元素在不需要时使用,而不是因为被迫使用。
  • 总体dom标记更少(提高了渲染性能并减少了内存开销)

就像不需要包装元素一样简单,您也不必使用一个包装元素。减少元素的数量是很棒的,但是我认为最大的好处是能够在jsx中呈现以前不可能的元素,并为包装器元素添加更好的语义,因为它们现在是可选的。

在此之前这是不可能的:

 <select>
    {this.renderOptions()}
 </select>

在React 15中浏览以下内容,您无法确定是否需要wrapper元素:

<span>
  <h1>Hello</h1>
  {this.getContent()}
</span>

2

根据reactjs.org 文档,最重要的需求<Fragment> </Fragment>是避免破坏HTML语义,而不是div。当我们使用div而不是<Fragment> </Fragment>HTML语义时。

要了解有关html语义的更多信息。请单击 ,并且在某些情况下,如果您使用div而不是Fragments,它将是无效的html,例如,查看以下代码:

class Columns extends React.Component {
  render() {
    return (
      <div>
        <td>Hello</td>
        <td>World</td>
      </div>
    );
  }
}

<table>
      <tr>
        <div>
          <td>Hello</td>
          <td>World</td>
        </div>
      </tr>
 </table>

碎片解决了这个问题。


1
  1. 使用<React.Fragment>...</React.Fragment>,我们可以在JSX元素中添加一个父标记,而无需在DOM中添加一个额外的节点。
  2. 您可以用React.Fragment替换多余的div标签
  3. 每次都写React.Fragment对您来说太长了。React.Fragment具有可以使用的简写语法。它是<>...</>.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.