Question Boucle à l'intérieur de React JSX


J'essaye de faire quelque chose comme ce qui suit dans React JSX (où ObjectRow est un composant séparé):

<tbody>
    for (var i=0; i < numrows; i++) {
        <ObjectRow/>
    } 
</tbody>

Je comprends et comprends pourquoi ce n'est pas valide JSX, puisque JSX correspond aux appels de fonction. Cependant, venant de la terre de modèle et étant nouveau à JSX, je ne suis pas sûr comment je réaliserais ceci (ajoutant un composant plusieurs fois).


736
2018-04-05 05:29


origine


Réponses:


Pensez-y comme si vous n'appeliez que des fonctions JavaScript. Vous ne pouvez pas mettre un for boucle à l'intérieur d'un appel de fonction:

return tbody(
    for (var i = 0; i < numrows; i++) {
        ObjectRow()
    } 
)

Mais vous pouvez faire un tableau, et ensuite passer dans:

var rows = [];
for (var i = 0; i < numrows; i++) {
    rows.push(ObjectRow());
}
return tbody(rows);

Vous pouvez utiliser essentiellement la même structure lorsque vous travaillez avec JSX:

var rows = [];
for (var i = 0; i < numrows; i++) {
    // note: we add a key prop here to allow react to uniquely identify each
    // element in this array. see: https://reactjs.org/docs/lists-and-keys.html
    rows.push(<ObjectRow key={i} />);
}
return <tbody>{rows}</tbody>;

Incidemment, mon exemple JavaScript est presque exactement ce que transforme cet exemple de JSX. Jouez avec Babel REPL pour avoir une idée de comment fonctionne JSX.


754
2018-04-05 05:39



Je ne sais pas si cela fonctionnera pour votre situation, mais souvent carte est une bonne réponse.

Si c'était votre code avec la boucle for:

<tbody>
    for (var i=0; i < objects.length; i++) {
        <ObjectRow obj={objects[i]} key={i}>
    } 
</tbody>

Vous pourriez l'écrire comme ça avec carte:

<tbody>
    {objects.map(function(object, i){
        return <ObjectRow obj={object} key={i} />;
    })}
</tbody>

Syntaxe ES6:

<tbody>
    {objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>

639
2018-04-05 05:46



Si vous ne disposez pas déjà d'un tableau map() comme la réponse de @ FakeRainBrigand, et que vous souhaitez intégrer cela afin que la mise en page source corresponde à la sortie plus proche que la réponse de @ SophieAlpert:

Avec la syntaxe ES2015 (ES6) (fonctions de propagation et de flèche)

http://plnkr.co/edit/mfqFWODVy8dKQQOkIEGV?p=preview

<tbody>
  {[...Array(10)].map((x, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

Re: transpilant avec Babel, son page de mises en garde dit ça Array.from est nécessaire pour la propagation, mais à l'heure actuelle (v5.8.23) qui ne semble pas être le cas lors de la diffusion d'un Array. j'ai un problème de documentation ouvert pour clarifier cela. Mais utilisez à vos risques et périls ou en polyfill.

Vanille ES5

Array.apply

<tbody>
  {Array.apply(0, Array(10)).map(function (x, i) {
    return <ObjectRow key={i} />;
  })}
</tbody>

Inline IIFE

http://plnkr.co/edit/4kQjdTzd4w69g8Suu2hT?p=preview

<tbody>
  {(function (rows, i, len) {
    while (++i <= len) {
      rows.push(<ObjectRow key={i} />)
    }
    return rows;
  })([], 0, 10)}
</tbody>

Combinaison de techniques issues d'autres réponses

Conservez la disposition source correspondant à la sortie, mais rendez la partie inline plus compacte:

render: function () {
  var rows = [], i = 0, len = 10;
  while (++i <= len) rows.push(i);

  return (
    <tbody>
      {rows.map(function (i) {
        return <ObjectRow key={i} index={i} />;
      })}
    </tbody>
  );
}

Avec la syntaxe ES2015 & Array méthodes

Avec Array.prototype.fill vous pourriez le faire comme une alternative à l'utilisation de la propagation comme illustré ci-dessus:

<tbody>
  {Array(10).fill(1).map((el, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

(Je pense que vous pourriez omettre n'importe quel argument pour fill(), mais je ne suis pas à 100% sur ce point.) Merci à @FakeRainBrigand pour corriger mon erreur dans une version antérieure de la fill() solution (voir révisions).

key

Dans tous les cas, le key attr allège un avertissement avec la construction de développement, mais n'est pas accessible dans l'enfant. Vous pouvez passer un attr supplémentaire si vous voulez que l'index soit disponible dans l'enfant. Voir Listes et clés pour discuter.


317
2018-04-14 14:08



Simplement en utilisant carte  Array méthode avec syntaxe ES6:

<tbody>
  {items.map(item => <ObjectRow key={item.id} name={item.name} />)} 
</tbody>

Ne pas oublier le key propriété.


52
2017-10-30 04:35



En utilisant Carte de tableau fonction est très moyen de faire une boucle à travers un Array des éléments et créer des composants selon eux dans Réagir, c'est une excellente façon de faire une boucle qui est très efficace et bien rangée pour faire vos boucles JSX, C'est ne pas la seule façon de le faire, mais le manière préférée. 

Aussi, n'oublie pas d'avoir un clé unique pour chaque itération au besoin. La fonction Map crée un index unique à partir de 0, mais il n'est pas recommandé d'utiliser l'index, mais si votre valeur est unique ou s'il existe une clé unique, vous pouvez les utiliser:

<tbody>
  {numrows.map(x=> <ObjectRow key={x.id} />)}
</tbody>

Aussi quelques lignes de MDN si vous n'êtes pas familier avec la fonction de carte sur Array:

map appelle une fonction de rappel fournie une fois pour chaque élément dans un   array, dans l'ordre, et construit un nouveau tableau à partir des résultats. rappeler   est invoqué uniquement pour les index du tableau qui ont des valeurs assignées,   y compris indéfini. Il n'est pas appelé pour les éléments manquants de la   array (c'est-à-dire, les index qui n'ont jamais été définis, qui ont été   supprimés ou auxquels aucune valeur n'a été affectée).

callback est invoqué avec trois arguments: la valeur de l'élément,   l'index de l'élément et l'objet Array traversé.

Si un paramètre thisArg est fourni à la carte, il sera utilisé comme   le rappel est cette valeur. Sinon, la valeur indéfinie sera utilisée comme   c'est cette valeur. Cette valeur finalement observable par le rappel est   déterminé selon les règles habituelles pour déterminer le vu   par une fonction.

map ne mute pas le tableau sur lequel il est appelé (bien que   callback, s'il est invoqué, peut le faire).


41
2018-05-16 13:37



Si vous utilisez déjà lodash, le _.times la fonction est pratique.

import React, { Component } from 'react';
import Select from './Select';
import _ from 'lodash';

export default class App extends Component {
    render() {
        return (
            <div className="container">
                <ol>
                    {_.times(3, i =>
                        <li key={i}>
                            <Select onSelect={this.onSelect}>
                                <option value="1">bacon</option>
                                <option value="2">cheez</option>
                            </Select>
                        </li>
                    )}
                </ol>
            </div>
        );
    }
}

33
2017-10-05 05:35



Vous pouvez également extraire en dehors du bloc de retour:

render: function() {
    var rows = [];
    for (var i = 0; i < numrows; i++) {
        rows.push(<ObjectRow key={i}/>);
    } 

    return (<tbody>{rows}</tbody>);
}

25
2018-01-04 05:53