如何包装返回多个表行的 React 组件并避免"<tr> cannot appear as a child of <div>"错误?



i具有一个称为orderitem的组件,该组件在其内部采用一个带有多个对象(至少两个)的对象,并将它们作为表中的多行呈现。表内将有多个订购组件。问题在于,在组件的渲染函数中,我无法返回多行。我只能返回一个组件,如果我将它们包裹在Div中,则说" <tr>不能以<div>的孩子出现"

代码看起来像这样(我遗漏了一些东西以更容易可读性)

Parent() {
  render() {
    return (
      <table>
        <tbody>
          {
            _.map(this.state.orderItems, (value, key) => {
              return <OrderItem value={value} myKey={key}/>
            })
          }
        </tbody>
      </table>
    )
  }
}
class OrderItem extends React.Component {
  render() {
    return (
      <div> // <-- problematic div
        <tr key={this.props.myKey}>
          <td> Table {this.props.value[0].table}</td>
          <td> Item </td>
          <td> Option </td>
        </tr>
        {this.props.value.map((item, index) => {
          if (index > 0) { // skip the first element since it's already used above
            return (
              <tr key={this.props.myKey + index.toString()}>
                <td><img src={item.image} alt={item.name} width="50"/> {item.name}</td>
                <td>{item.selectedOption}</td>
              </tr>
            )
          }
        })}
      </div>
    )
  }
}

有没有一种方法可以返回那些行并将它们放在同一张桌子中而无需包裹在DIV中并遇到错误?我意识到我可以为每个组件制作一个单独的表格,但这会抛出我的格式。

React 16现在在这里营救,您现在可以使用 React.Fragment渲染元素列表而无需包装到父元素中。您可以做这样的事情:

render() {
  return (
    <React.Fragment>
      <tr>
        ...
      </tr>
    </React.Fragment>
  );
}

是的!可以将项目映射到表中的多个表行。一种不引发控制台错误且语义上的解决方案实际上是正确的,是将tbody元素用作根组件并根据需要填充的行。

items.map(item => (
   <tbody>
       <tr>...</tr>
       <tr>...</tr>
   </tbody>
))

以下帖子涉及有关它的道德问题,并解释了为什么是的,我们可以使用多个tbody元素我们可以拥有多个&lt; tbody&gt;在同一&lt;??

一种方法是将OrderItem分为两个组件,将渲染逻辑移动到方法Parent.renderOrderItems

class Parent extends React.Component {
  renderOrderItems() {
    const rows = []
    for (let orderItem of this.state.orderItems) {
      const values = orderItem.value.slice(0)
      const headerValue = values.shift()
      rows.push(
        <OrderItemHeaderRow table={headerValue.table} key={orderItem.key} />
      )
      values.forEach((item, index) => {
        rows.push(
          <OrderItemRow item={item} key={orderItem.key + index.toString()} />
        )
      })
    }
    return rows
  }
  render() {
    return (
      <table>
        <tbody>
          { this.renderOrderItems() }
        </tbody>
      </table>
    )
  }
}
class OrderItemHeaderRow extends React.Component {
  render() {
    return (
      <tr>
        <td> Table {this.props.table}</td>
        <td> Item </td>
        <td> Option </td>
      </tr>
    )
  }
}
class OrderItemRow extends React.Component {
  render() {
    const { item } = this.props
    return (
      <tr>
        <td>
          <img src={item.image} alt={item.name} width="50"/>
          {item.name}
        </td>
        <td>
          {item.selectedOption}
        </td>
      </tr>
    )
  }
}

似乎没有办法清洁,因此更容易的解决方案是将整个桌子放入组件中,只有多个表格并找出格式。

Parent() {
   render() {
       return (
           {_.map(this.state.orderItems, (value, key) => {
               return <OrderItem value={value} myKey={key} key={key}/>
           })}
       )
   }
}

class OrderItem extends React.Component {
    render() {
        return (
            <table>
                <tbody>
                   <tr>
                       <td> Table {this.props.value[0].table}</td>
                       <td> Item </td>
                       <td> Option </td>
                    </tr>
                    {this.props.value.map((item, index) => {
                        if (index > 0) { // skip the first element since it's already used above
                            return (
                                <tr key={this.props.myKey + index.toString()}>
                                    <td> <img src={item.image} alt={item.name} width="50"/> {item.name}</td>  
                                    <td>{item.selectedOption}</td>
                                </tr>
                            )
                        }
                    })}
                </tbody>
            </table>
        )
    }
}

这是一个古老的问题,但也许有人偶然发现了它。由于我尚未发表评论,这是@trevorgk的答案的一些补充:

我用它来渲染一个具有每项多行的表(约1000个项目,大约有2000行,带有15列),并注意到Firefox的性能确实很差(即使在57中)。

我有纯粹的组件渲染每个项目(一个&lt; hody&gt;每个包含两个行的项目),每个项目包含一个(受控的)复选框。

单击复选框时,Firefox花了十秒钟以上的时间才能更新 - 尽管由于纯粹的组件,实际上仅实际更新了一个项目。Chrome的更新最多花费了一秒钟。

我切换到16,我注意到没有区别。然后我使用了新的很棒!!!从组件的渲染功能中返回数组并摆脱1000&lt; tbody&gt;元素。Chrome的性能大致相同,而Firefox的"飞涨"至大约半秒以进行更新(对Chrome没有感知差异)

在我的情况下,解决方案是返回数组而不是片段:

    return [
        <TrHeader />,
        <TrRows />
    ];

最新更新