59 votes

Comment emballer un composant React qui renvoie plusieurs lignes de la table et évite le " <tr> ne peut pas apparaître comme un enfant de <div> " Erreur?

J'ai un composant appelé OrderItem qui prend un objet avec plusieurs objets (au moins deux) à l'intérieur, et les rend comme plusieurs lignes dans une table. Il y aura plusieurs OrderItem composants à l'intérieur de la table. Le problème est que dans la composante de la fonction rendu, je ne peux pas retourner plusieurs lignes. Je ne peux que renvoyer un seul composant, et si je les envelopper dans un div, il est dit " <tr> ne peut pas apparaître comme un enfant de <div>"

Le code ressemble à quelque chose comme ceci (j'ai laissé certaines choses pour la lisibilité)

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>
        )
    }
}

Est il possible que je peux le retour de ces multiples lignes et dans le même tableau, sans les envelopper dans une div et d'avoir une erreur? Je me rends compte que je peux faire un tableau distinct pour chaque composant, mais ça en jette ma mise en forme un peu.

39voto

essaji Points 528

React 16 est maintenant là pour sauver, vous pouvez maintenant utiliser React.Fragment pour rendre la liste des éléments sans l'envelopper dans un élément parent. Vous pouvez faire quelque chose comme ça:

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

30voto

trevorgk Points 1028

Oui!! Il est possible pour les éléments de la carte à plusieurs lignes de la table à l'intérieur d'un tableau. Une solution qui permet de ne pas jeter les erreurs de la console et de la sémantique est correcte, est d'utiliser un tbody élément le composant racine, et le remplir avec autant de lignes que nécessaire.

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

Le post suivant traite les questions d'éthique à ce sujet et explique pourquoi oui, on peut utiliser plusieurs tbodyéléments Peut-on avoir plusieurs <tbody> même <table>?

14voto

Jomel Imperio Points 789

Une approche consiste à scinder OrderItem en deux composants, en déplaçant la logique de rendu dans une méthode 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>
    )
  }
}
 

4voto

Pedram Points 2184

Il semble qu'il n'y ait aucun moyen de les emballer proprement. La solution la plus simple consiste donc simplement à placer le tableau entier dans le composant, à disposer de plusieurs tableaux et à déterminer la mise en forme.

 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>
        )
    }
}
 

4voto

Markus Points 63

C'est une vieille question, mais peut-être que quelqu'un trébuche sur elle. Depuis que je ne peut pas commenter pourtant, voici un peu plus de la réponse de @trevorgk:

J'ai utilisé ce pour rendre un tableau avec plusieurs lignes par article (environ 1000 articles résultant en environ 2000 lignes avec 15 colonnes) et remarqué vraiment de la mauvaise performance avec Firefox (même dans 57).

J'ai eu des composants purs rendu de chaque élément (un <body> par élément contenant deux lignes chacune) et chaque élément a (contrôlée) de case à cocher.

Lorsque vous cliquez sur la case à cocher Firefox a pris plus de dix secondes pour mettre à jour - si un seul point a été effectivement mises à jour en raison de composants purs. Chrome est mise à jour a été à plus d'une demi-seconde.

Je suis passé à Réagir 16 et j'ai remarqué aucune différence. Ensuite, j'ai utilisé le nouveau GÉNIAL!!! fonction de retour d'un tableau à partir d'un composant de rendu de fonction et de se débarrasser de l'1000 <tbody> éléments. Google Chrome, le rendement était d'environ la même alors que Firefox est "explosé" à environ une demi-seconde pour une mise à jour (pas de différence perçue à Chrome)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X