如何避免在 React 中额外包装 <div>?

Posted

技术标签:

【中文标题】如何避免在 React 中额外包装 <div>?【英文标题】:How to avoid extra wrapping <div> in React? 【发布时间】:2016-02-19 08:44:01 【问题描述】:

今天我开始学习 ReactJS 并在一个小时后遇到了这个问题.. 我想在页面上的 div 内插入一个有两行的组件。下面是我所做的简化示例。

我有一个 html

<html>
..
  <div id="component-placeholder"></div>
..
</html>

渲染函数如下:

...
render: function() 

    return(
        <div className="DeadSimpleComponent">
            <div className="DeadSimpleComponent__time">10:23:12</div >
            <div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
        </div>
    )

....

下面我叫渲染:

ReactDOM.render(<DeadSimpleComponent/>, document.getElementById('component-placeholder'));

生成的 HTML 如下所示:

<html>
..
  <div id="component-placeholder">
    <div class="DeadSimpleComponent">
            <div class="DeadSimpleComponent__time">10:23:12</div>
            <div class="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
    </div>
</div>
..
</html>

React 迫使我将所有内容包装在一个 div“DeadSimpleComponent”中,这让我很不高兴。在没有显式 DOM 操作的情况下,最好和最简单的解决方法是什么?

2017 年 7 月 28 日更新:React 的维护者在 React 16 Beta 1 中添加了这种可能性

由于React 16.2,你可以这样做:

render() 
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  );

【问题讨论】:

完美的命名习惯 ;-) 我可以看看你的 HTML 文件吗?我误读了你的问题。不过我可能有一个解决方法。 这样的:jsfiddle.net/qawumm3v 您对具有单个元素的组件有疑问?真的吗? 什么意思?我只是在尝试 React,它应该不会很复杂.. 但是限制看起来很烦人。 【参考方案1】:

在 React 版本 (16.0)]1 中删除了此要求,因此现在您可以避免使用该包装器。

你可以使用React.Fragment来渲染一个元素列表而无需创建父节点,官方示例:

render() 
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  );

更多:Fragments

【讨论】:

好消息 DmitryUlyanets。有计划的发布日期吗? 自2017年9月26日起发布,见reactjs.org/blog/2017/09/26/react-v16.0.html 也可以使用简写: > 代替 【参考方案2】:

2017 年 12 月 5 日更新: React v16.2.0 现在完全支持片段渲染,改进了对从组件渲染方法返回多个子节点的支持,而无需在子节点中指定键:

render() 
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  );

如果您使用的是 v16.2.0 之前的 React 版本,也可以使用 &lt;React.Fragment&gt;...&lt;/React.Fragment&gt; 代替:

render() 
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  );


原文:

React v16.0 引入了在 render 方法中返回一个元素数组而不将其包装在 div 中:https://reactjs.org/blog/2017/09/26/react-v16.0.html

render() 
  // No need to wrap list items in an extra element!
  return [
    // Don't forget the keys :)
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];

目前,每个元素都需要一个键以避免出现键警告,但这可能会在未来的版本中更改:

未来,我们可能会在 JSX 中添加一个特殊的片段语法, 不需要钥匙。

【讨论】:

> 的新速记语法很棒。但是,我仍然对此有很多复杂的感觉。 @ThulaniChivandikwa 您介意说出您对速记语法的疑虑吗? 我认为这更多是关于空标签的概念在 JSX 中很奇怪并且不是很直观,除非您确切知道它的作用。【参考方案3】:

你可以使用:

render()
    return (
        <React.Fragment>
           <div>Some data</div>
           <div>Som other data</div>
        </React.Fragment>
    )

更多详情请参考this documentation。

【讨论】:

【参考方案4】:

使用 [] 而不是 () 来包装整个返回。

render: function() 
  return[
    <div className="DeadSimpleComponent__time">10:23:12</div >
    <div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
  ]

【讨论】:

【参考方案5】:

我创建了一个组件来包装没有 DIV 的子组件。它被称为影子包装器:https://www.npmjs.com/package/react-shadow-wrapper

【讨论】:

我在你的包裹上发布了一个问题,你能看看吗?谢谢【参考方案6】:

这仍然是必需的但是 React 现在确保创建元素而不创建额外的 DOM 元素。

需要额外的包装(通常使用父 div),因为 Reacts createElement 方法需要 type 参数,即 either a tag name string (such as 'div' or 'span'), a React component type (a class or a function)。但这是在他们介绍 React Fragment 之前。

参考this NEW api doc for createElement

React.createElement :创建并返回给定类型的新 React 元素。 type 参数可以是标签名称字符串(例如 'div' 或 'span')、React 组件类型(类或函数)、或 React 片段类型

这里是官方例子,参考React.Fragment。

render() 
  return (
    <React.Fragment>
      Some text.
      <h2>A heading</h2>
    </React.Fragment>
  );

【讨论】:

【参考方案7】:

您将无法摆脱 div 元素。 React.render() 需要返回一个有效的 DOM 节点。

【讨论】:

div 被忽略,Knockout.JS 做同样的事情。在组件的外部有一个没有样式的 div 不会产生任何影响。 @ChrisHawkes,不同意。一个包装器 div 会影响 css 选择器。 在使用语义元素时,您不想完全成为 React 组件,这会成为一个问题。假设有一个带有页眉和页脚元素的 section-tag,在它们之间有一个 google map-container,我们不想在 React 中使用它。然后将 header 作为 React 组件,将 Footer 作为 React 组件会很好,而不必在 React 组件内部包含额外的 div:s ......如果你完全关心 html,那是愚蠢的设计你输出...【参考方案8】:

这是渲染“半透明”组件的一种方法:

import React from 'react'

const Show = (props) => 
  if (props.if || false) 
    return (<React.Fragment>props.children</React.Fragment>)
  
  return '';
;

----


<Show if=yomama.so.biq>
    <img src="https://yomama.so.biq">
    <h3>Yoamama</h3>
<Show>

【讨论】:

【参考方案9】:

也有解决方法。下面的代码块生成片段而不需要 React.Fragment。

return [1,2,3].map(i=>
if(i===1) return <div key=i>First item</div>
if(i===2) return <div key=i>Second item</div>
return <div key=i>Third item</div>
)

【讨论】:

【参考方案10】:

我知道这个问题已经得到解答,你当然可以使用 React.Fragment,它不会创建节点,但可以让你对 div 之类的东西进行分组。

另外,如果你想玩得开心,你可以实现(并学习很多东西)一个 React 模式,它可以删除多余的 div,为此我真的想分享一个很棒的视频,介绍如何在 react 代码库上做到这一点自己。

https://www.youtube.com/watch?v=aS41Y_eyNrU

这当然不是你在实践中会做的事情,但它是一个很好的学习机会。

【讨论】:

以上是关于如何避免在 React 中额外包装 <div>?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用空格:React 上的“预包装”

如何删除额外的 div 包装器

React 组件中是不是有任何必需的 div 包装器

使用带有文本的 glyphicon 时如何避免额外的空间?

我有一个相互重叠的 flex 包装 div 容器。这些可能是不同的高度并包裹多次。如何避免重叠?

如何避免相对布局中可绘制背景的额外高度?