Boucle à l'intérieur de React JSX

1279

J'essaie de faire quelque chose comme ce qui suit dans React JSX(où ObjectRow est un composant distinct):

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

Je me rends compte et je comprends pourquoi cela n'est pas valide JSX, car il JSXcorrespond aux appels de fonction. Cependant, venant de la terre des modèles et étant nouveau dans JSX, je ne sais pas comment j'obtiendrais ce qui précède (en ajoutant un composant plusieurs fois).

Ben Roberts
la source
38
Il est important de noter que dans JSX, vous avez besoin des balises {} autour de votre syntaxe JavaScript. Cela peut aider facebook.github.io/react/docs/… .
Isaiah Grey
30
let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
OverCoder
@OverCoder pourquoi mettriez-vous un retour entier dans la balise {} ce serait => return <h1> {todo.title} </h1> N'est-ce pas?
pravin poudel
1
@pravinpoudel en fait cette réponse est ancienne, plus comme let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

Réponses:

1205

Pensez-y comme si vous appeliez simplement des fonctions JavaScript. Vous ne pouvez pas utiliser une forboucle où iraient les arguments d'un appel de fonction:

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

Voyez comment la fonction tbodypasse une forboucle comme argument, et bien sûr, c'est une erreur de syntaxe.

Mais vous pouvez créer un tableau, puis le passer en argument:

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>;

Soit dit en passant, mon exemple JavaScript est presque exactement ce que cet exemple de JSX transforme. Jouez avec Babel REPL pour avoir une idée du fonctionnement de JSX.

Sophie Alpert
la source
3
Il est possible que le compilateur ait changé, car cet exemple ne semble pas se compiler dans le compilateur jsx , mais l'utilisation de map comme dans la réponse de FakeRainBrigand ci-dessous semble se compiler correctement.
rav
9
Je peux vous promettre que le dernier exemple se compile toujours correctement sur le dernier compilateur JSX.
Sophie Alpert du
3
Cela fonctionne bien. La réponse de FakeRainBrigand fonctionne pour une simple itération de tableau, mais cette réponse est un must pour les scénarios où vous ne pouvez pas utiliser map(par exemple, vous n'avez pas une collection stockée dans une variable).
Kelvin
52
React doit mettre à jour dom efficacement, dans ce cas, le parent doit attribuer un keyà chaque childern. REF: facebook.github.io/react/docs/…
qsun
7
Cet exemple fonctionnera, mais il manque des bits importants comme la keypropriété et également un style de code qui n'est pas vraiment utilisé dans les bases de code React. Veuillez considérer cette réponse stackoverflow.com/questions/22876978/loop-inside-react-jsx/… comme une réponse correcte.
okonetchnikov
867

Je ne sais pas si cela fonctionnera pour votre situation, mais souvent la 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 pouvez l'écrire comme ceci avec la 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>
Brigand
la source
43
La carte a plus de sens si l'itérée est un tableau; Une boucle for est appropriée s'il s'agit d'un nombre.
Code Whisperer
26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>en utilisant le support ES6 de Reactify ou Babel.
Distortum
3
+1. J'utilise même cela avec un ul (liste non ordonnée). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>en utilisant TypeScript
Roberto C Navarro
5
c'est super, mais vous ne pouvez pas cartographier sur un objet .. pour cela j'utiliseraisfor..in
Damon
4
Gardez à l'esprit que l'ordre des clés est arbitraire lorsque vous utilisez Object.keys. Je trouve que le stockage de l'ordre des clés séparément fonctionne bien, ainsi que l'ordre sur l'objet littéral si nécessaire. Cela me permet d'écrire du code commethis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr
444

Si vous n'avez pas encore de tableau pour map()aimer la réponse de @ FakeRainBrigand, et que vous souhaitez l'inclure de sorte que la disposition 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: transpiling avec Babel, sa page de mises en garde dit que Array.fromc'est nécessaire pour la propagation, mais à l'heure actuelle ( v5.8.23) cela ne semble pas être le cas lors de la propagation d'un réel Array. J'ai un problème de documentation ouvert pour clarifier cela. Mais utilisez à vos risques et périls ou polyfill.

Vanilla 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 d'autres réponses

Conservez la disposition source correspondant à la sortie, mais rendez la partie en ligne 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 et les Arrayméthodes ES2015

Avec, Array.prototype.fillvous pouvez faire cela comme une alternative à l'utilisation de spread comme illustré ci-dessus:

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

(Je pense que vous pourriez en fait omettre tout argument fill(), mais je ne suis pas à 100% là-dessus.) Merci à @FakeRainBrigand d'avoir corrigé mon erreur dans une version antérieure de la fill()solution (voir les révisions).

key

Dans tous les cas, l' keyattr atténue un avertissement avec la build de développement, mais n'est pas accessible à 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 discussion.

JMM
la source
2
Et alors yield? Pousser des éléments dans un tableau intermédiaire est un peu moche quand nous avons des générateurs. Travaillent-ils?
mpen
2
@Mark Je ne sais pas si les générateurs sont vraiment applicables ici. L'élément clé pour cela dans le contexte de JSX est une expression qui renvoie un tableau. Donc, si vous deviez utiliser un générateur, vous le répandriez probablement de toute façon, et ce serait probablement plus détaillé que les solutions basées sur ES2015 ici.
JMM
2
Comment est- ce plus verbeux? Et pourquoi JSX n'accepterait-il pas des tableaux itérables, pas seulement des tableaux?
mpen
2
@Mark C'est en effet moins verbeux que l'exemple (ES5) IIFE que j'ai utilisé, mais c'est beaucoup plus verbeux que la [...Array(x)].map(() => <El />))version, qui je pense est la plus élégante, et pourquoi je l'ai présentée. Re: la deuxième question, c'est un grand point. Il ne semble rien y avoir sur JSX qui l'empêche, donc cela dépend de ce que React ou un autre consommateur de JSX transformé fait avec les arguments enfants, ce que je ne pourrais pas dire sans regarder la source. Savez-vous? C'est une question intrigante.
JMM
3
@corysimmons Cool, merci pour l'info sur fill(). Je me souviens maintenant que la raison pour laquelle j'hésitais à ce sujet est une question sur la façon dont le caractère optionnel des paramètres est indiqué dans la spécification ES (il faut que j'y réfléchisse un jour). La virgule n'est qu'un moyen d'éluder un élément de tableau - dans ce cas, le premier. Vous pouvez le faire si vous voulez que les index soient de 1..longueur du tableau que vous étalez plutôt que de 0..longueur-1 du tableau étalé (car les éléments élidés contribuent simplement à la longueur du tableau et ne ' t ont une propriété correspondante).
JMM
85

En utilisant simplement la méthode map Array avec la syntaxe ES6:

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

N'oubliez pas la keypropriété.

danielfeelfine
la source
J'ajoute une clé aléatoire 'Math.random ()' au lieu de l'id ça ne marche pas bien quand setState à l'intérieur des enfants, avez-vous une idée pourquoi?
Oliver D
82

L'utilisation de la fonction Array map est un moyen très courant de parcourir un tableau d'éléments et de créer des composants en fonction de React , c'est un excellent moyen de faire une boucle qui est assez efficace et bien rangée pour faire vos boucles en JSX , ce n'est pas le seul façon de le faire, mais la façon préférée.

N'oubliez pas non plus d'avoir une clé unique pour chaque itération, au besoin. La fonction de carte crée un index unique à partir de 0, mais il n'est pas recommandé d'utiliser l'index produit, 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>

En outre, 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 d'un tableau, dans l'ordre, et construit un nouveau tableau à partir des résultats. le rappel n'est invoqué que pour les index du tableau auxquels des valeurs ont été attribuées, y compris undefined. Il n'est pas appelé pour les éléments manquants du tableau (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).

Le rappel 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 pour mapper, il sera utilisé comme rappel de cette valeur. Sinon, la valeur non définie sera utilisée comme sa valeur this. Cette valeur finalement observable par le rappel est déterminée selon les règles habituelles de détermination de ce vu par une fonction.

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

Alireza
la source
Array#mapn'est pas asynchrone!
philraj
52

Si vous utilisez déjà lodash, la _.timesfonction 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>
        );
    }
}
mpen
la source
1
Array.prototype.map pourrait être une excellente option ici si vous n'incluez pas une bibliothèque telle que lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Isaiah Grey
1
@IsaiahGrey Seulement si vous avez déjà un tableau. Parfois, vous voulez simplement répéter des choses plusieurs fois.
mpen
1
Oui bien sûr! Beaucoup d'approches différentes à coup sûr en fonction des données réelles. J'ai constaté que le plus souvent dans notre processus de développement, nous avons pu intégrer la carte en raison de la façon dont les données sont modélisées. Excellent exemple en utilisant lodash! Btw, utilisez-vous la syntaxe d'initialisation de propriété pour lier vos méthodes à vos composants?
Isaiah Grey
4
@IsaiahGrey Je pense qu'on les appelle simplement définitions de méthodes
ES6
41

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>);
}
Brandon Sibeitokgong
la source
34

Je sais que c'est un vieux fil, mais vous voudrez peut- être vérifier les modèles React , qui vous permettent d'utiliser des modèles de style jsx dans react, avec quelques directives (telles que rt-repeat).

Votre exemple, si vous avez utilisé des modèles de réaction, serait:

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>
Etai
la source
Pourquoi utiliser une bibliothèque supplémentaire alors que le javascript ordinaire a déjà fourni une solution avec différents types de boucle for ou de méthode Array.prototype.map pour résoudre le problème? J'ai moi-même déjà utilisé les deux méthodes javascript simples dans mon projet actuel qui fonctionnent bien. Avoir l'habitude d'utiliser autant que possible des moyens javascript simples m'aide à améliorer mes compétences en javascript. J'utilise uniquement des bibliothèques supplémentaires lorsqu'il semble difficile de trouver des solutions à certains problèmes, tels que le routage avec React-Router.
Lex Soft
27

Il existe plusieurs façons de procéder. JSX est finalement compilé en JavaScript, donc tant que vous écrivez du JavaScript valide, vous serez bon.

Ma réponse vise à consolider toutes les merveilleuses façons déjà présentées ici:

Si vous n'avez pas de tableau d'objets, simplement le nombre de lignes:

dans le returnbloc, en créant Arrayet en utilisant Array.prototype.map:

render() {
  return (
    <tbody>
      {Array(numrows).fill(null).map((value, index) => (
        <ObjectRow key={index}>
      ))}
    </tbody>
  );
}

en dehors du returnbloc, utilisez simplement une boucle for JavaScript normale:

render() {
  let rows = [];
  for (let i = 0; i < numrows; i++) {
    rows.push(<ObjectRow key={i}/>);
  } 
  return (
    <tbody>{rows}</tbody>
  );
}

expression de fonction immédiatement invoquée:

render() {
  return (
    <tbody>
      {() => {
        let rows = [];
        for (let i = 0; i < numrows; i++) {
          rows.push(<ObjectRow key={i}/>);
        }
        return rows;
      }}
    </tbody>
  );
}

Si vous avez un tableau d'objets

dans le returnbloc, .map()chaque objet d'un <ObjectRow>composant:

render() {
  return (
    <tbody>
      {objectRows.map((row, index) => (
        <ObjectRow key={index} data={row} />
      ))}
    </tbody>
  );
}

en dehors du returnbloc, utilisez simplement une boucle for JavaScript normale:

render() {
  let rows = [];
  for (let i = 0; i < objectRows.length; i++) {
    rows.push(<ObjectRow key={i} data={objectRows[i]} />);
  } 
  return (
    <tbody>{rows}</tbody>
  );
}

expression de fonction immédiatement invoquée:

render() {
  return (
    <tbody>
      {(() => {
        const rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}
Yangshun Tay
la source
2
Excellentes réponses: diverses techniques, toutes n'utilisent que du javascript simple qui montre la puissance du javascript, grâce à ses différentes façons de faire des tâches similaires.
Lex Soft
24

si numrows est un tableau, et c'est très simple.

<tbody>
   {numrows.map(item => <ObjectRow />)}
</tbody>

Le type de données de tableau dans React est très meilleur, le tableau peut sauvegarder un nouveau tableau et prendre en charge le filtre, réduire, etc.

lulin
la source
Ce n'est pas une réponse décente car elle n'utilise pas de clé.
kojow7
21

Il existe plusieurs réponses indiquant l'utilisation de la mapdéclaration. Voici un exemple complet utilisant un itérateur dans le composant FeatureList pour répertorier les composants Feature basés sur une structure de données JSON appelée features .

const FeatureList = ({ features, onClickFeature, onClickLikes }) => (
  <div className="feature-list">
    {features.map(feature =>
      <Feature
        key={feature.id}
        {...feature}
        onClickFeature={() => onClickFeature(feature.id)}
        onClickLikes={() => onClickLikes(feature.id)}
      />
    )}
  </div>
); 

Vous pouvez afficher le code FeatureList complet sur GitHub. Le dispositif de fonctionnalités est répertorié ici .

Manav Sehgal
la source
Lorsque je traite des données JSON, par exemple lors de la récupération de données à partir d'une base de données à l'aide de l'API fetch, je m'appuie sur la méthode Array.prototype.map. C'est un moyen pratique et éprouvé à cet effet.
Lex Soft
17

Pour boucler plusieurs fois et revenir, vous pouvez y parvenir à l'aide de fromet map:

<tbody>
  {
    Array.from(Array(i)).map(() => <ObjectRow />)
  }
</tbody>

i = number of times


Si vous souhaitez attribuer des ID de clé uniques aux composants rendus, vous pouvez les utiliser React.Children.toArraycomme proposé dans la documentation React

React.Children.toArray

Renvoie la structure de données opaque des enfants sous forme de tableau plat avec des clés affectées à chaque enfant. Utile si vous souhaitez manipuler des collections d'enfants dans vos méthodes de rendu, en particulier si vous souhaitez réorganiser ou découper this.props.children avant de le transmettre.

Remarque:

React.Children.toArray()modifie les clés pour préserver la sémantique des tableaux imbriqués lors de l'aplatissement des listes d'enfants. C'est-à-dire que toArray préfixe chaque clé du tableau renvoyé afin que la clé de chaque élément soit étendue au tableau d'entrée qui la contient.

<tbody>
  {
    React.Children.toArray(
      Array.from(Array(i)).map(() => <ObjectRow />)
    )
  }
</tbody>
Jee Mok
la source
17

Si vous choisissez de convertir cette méthode return () de la méthode de rendu , l'option la plus simple serait d'utiliser la méthode map () . Mappez votre tableau dans la syntaxe JSX à l'aide de la fonction map (), comme illustré ci-dessous (la syntaxe ES6 est utilisée ).


Composant parent intérieur :

<tbody>
   { objectArray.map(object => <ObjectRow key={object.id} object={object.value}>) }
</tbody>

Veuillez noter l' keyattribut ajouté à votre composant enfant. Si vous n'avez pas fourni d'attribut clé, vous pouvez voir l'avertissement suivant sur votre console.

Avertissement: chaque enfant d'un tableau ou d'un itérateur doit avoir un accessoire "clé" unique.

Remarque: Une erreur courante est indexque les gens utilisent comme clé lors de l'itération, l'utilisation indexde l'élément comme clé est un anti-modèle et vous pouvez en lire plus ici . En bref, si ce n'est PAS une liste statique, n'utilisez jamais indexde clé.


Maintenant, au niveau du composant ObjectRow , vous pouvez accéder à l'objet à partir de ses propriétés.

À l'intérieur du composant ObjectRow

const { object } = this.props

ou

const object = this.props.object

Cela devrait vous récupérer l'objet que vous avez passé du composant parent à la variable objectdans le composant ObjectRow . Vous pouvez maintenant cracher les valeurs de cet objet en fonction de votre objectif.


Références :

méthode map () en Javascript

ECMA Script 6 ou ES6

bharadhwaj
la source
16

disons que nous avons un tableau d'articles dans votre état:

[{name: "item1", id: 1}, {name: "item2", id: 2}, {name: "item3", id: 3}]

<tbody>
    {this.state.items.map((item) => {
        <ObjectRow key={item.id} name={item.name} />
    })} 
</tbody>
Jan Franz Palngipang
la source
Je pense que vous devrez peut-être vous débarrasser de {} après la carte (élément), qui semblait les travailler pour moi.
Ian
15

Une possibilité ES2015 / Babel utilise une fonction de générateur pour créer un tableau de JSX:

function* jsxLoop(times, callback)
{
    for(var i = 0; i < times; ++i)
        yield callback(i);
}

...

<tbody>
    {[...jsxLoop(numrows, i =>
        <ObjectRow key={i}/>
    )]}
</tbody>
David Q Hogan
la source
15

... Ou vous pouvez également préparer un tableau d'objets et le mapper à une fonction pour obtenir la sortie souhaitée. Je préfère cela, car cela m'aide à maintenir la bonne pratique de codage sans logique à l'intérieur du retour de rendu.

render() {
const mapItem = [];
for(let i =0;i<item.length;i++) 
  mapItem.push(i);
const singleItem => (item, index) {
 // item the single item in the array 
 // the index of the item in the array
 // can implement any logic here
 return (
  <ObjectRow/>
)

}
  return(
   <tbody>{mapItem.map(singleItem)}</tbody>
  )
}
Rafi Ud Daula Refat
la source
15

Utilisez simplement .map() pour parcourir votre collection et renvoyer les <ObjectRow>articles avec des accessoires de chaque itération.

En supposant qu'il objectsy a un tableau quelque part ...

<tbody>
  { objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
Joshua Michael Waggoner
la source
15

ES2015 Array.from avec la touche de fonction carte +

Si vous n'avez rien à .map()utiliser Array.from()avec la mapfonction pour répéter des éléments:

<tbody>
  {Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>
Faire Async
la source
15

J'utilise ceci:

gridItems = this.state.applications.map(app =>
          <ApplicationItem key={app.Id} app={app } />
);

PS: n'oubliez jamais la clé ou vous aurez beaucoup d'avertissements!

JC
la source
Ou utilisez l'index du tableau si vos éléments n'ont pas de .Idpropriété, commeitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur
13

J'ai tendance à privilégier une approche où la logique de programmation se produit en dehors de la valeur de retour de render . Cela aide à garder ce qui est réellement rendu facile à grok.

Je ferais probablement quelque chose comme:

import _ from 'lodash';

...

const TableBody = ({ objects }) => {
  const objectRows = objects.map(obj => <ObjectRow object={obj} />);      

  return <tbody>{objectRows}</tbody>;
} 

Certes, c'est une si petite quantité de code que l'inclure pourrait bien fonctionner.

Adam Donahue
la source
Grand fan de la carte de lodash pour parcourir les objets. Je serais enclin à import { map } from 'lodash'ce que vous n'importiez pas toutes les fonctions lodash si vous n'en avez pas besoin.
Stretch0
De nos jours, nous n'avons même pas besoin d'une carte lodash - il suffit de cartographier directement le tableau.
Adam Donahue
Oui, mais vous ne pouvez pas parcourir un objet avec es6 map(), uniquement des tableaux. C'est ce que je disais, lodash est bon pour faire une boucle sur un objet.
Stretch0
Je pensais que tu voulais dire objectscomme dans une liste de choses, mon erreur.
Adam Donahue
12

vous pouvez bien sûr résoudre avec un .map comme suggéré par l'autre réponse. Si vous utilisez déjà babel, vous pourriez penser à utiliser les instructions jsx-control. Elles nécessitent un peu de réglage, mais je pense que cela vaut en termes de lisibilité (en particulier pour les développeurs non réactifs). Si vous utilisez un linter, il y a aussi des instructions eslint-plugin-jsx-control

Jurgo Boemo
la source
12

Votre code JSX sera compilé en code JavaScript pur, toutes les balises seront remplacées par des ReactElementobjets. En JavaScript, vous ne pouvez pas appeler une fonction plusieurs fois pour collecter les variables renvoyées.

C'est illégal, la seule façon est d'utiliser un tableau pour stocker les variables renvoyées par la fonction.

Ou vous pouvez utiliser Array.prototype.mapce qui est disponible depuis JavaScript ES5 pour gérer cette situation.

Peut-être que nous pouvons écrire un autre compilateur pour recréer une nouvelle syntaxe JSX pour implémenter une fonction de répétition comme celle d' Angularng-repeat .

hlissnake
la source
12

Cela peut être fait de multiples façons.

  1. Comme suggéré ci-dessus, avant de returnstocker tous les éléments du tableau
  2. Boucle à l'intérieur return

    Méthode 1

     let container =[];
        let arr = [1,2,3] //can be anything array, object 
    
        arr.forEach((val,index)=>{
          container.push(<div key={index}>
                         val
                         </div>)
            /** 
            * 1. All loop generated elements require a key 
            * 2. only one parent element can be placed in Array
            * e.g. container.push(<div key={index}>
                                        val
                                  </div>
                                  <div>
                                  this will throw error
                                  </div>  
                                )
            **/   
        });
        return (
          <div>
             <div>any things goes here</div>
             <div>{container}</div>
          </div>
        )

    Méthode 2

       return(
         <div>
         <div>any things goes here</div>
         <div>
            {(()=>{
              let container =[];
              let arr = [1,2,3] //can be anything array, object 
              arr.forEach((val,index)=>{
                container.push(<div key={index}>
                               val
                               </div>)
                             });
                        return container;     
            })()}
    
         </div>
      </div>
    )
abhirathore2006
la source
Ouais. Dans mon projet actuel, j'utilise la méthode 1, c'est-à-dire en utilisant Array.prototype, la méthode forEach () pour créer un élément de sélection HTML qui est rempli par les données de la base de données. Cependant, je les remplacerai plus probablement par la méthode Array.prototype.map (), car la méthode map semble plus compacte (moins de code).
Lex Soft
10

Voici une solution simple.

var Object_rows=[];
for (var i=0; i < numrows; i++) {
    Object_rows.push(<ObjectRow/>)
} 
<tbody>
  {Object_rows}
</tbody>

Aucun mappage et code complexe requis. Il vous suffit de pousser les lignes vers le tableau et de renvoyer les valeurs pour le rendre.

Javasamurai
la source
Lors de la création d'un élément de sélection html, cette technique similaire était celle qui m'est venue à l'esprit en premier, donc je l'ai utilisée, bien que j'utilise la méthode forEach (). Mais quand j'ai relu le document React sur des sujets de listes et de clés, j'ai constaté qu'ils utilisent la méthode map () comme le montrent également plusieurs réponses ici. Cela me fait penser que c'est la voie préférée. Je suis d'accord, car il semble plus compact (moins de code).
Lex Soft
9

Puisque vous écrivez la syntaxe Javascript dans le code JSX, vous devez envelopper votre Javascript entre accolades.

row = () => {
   var rows = [];
   for (let i = 0; i<numrows; i++) {
       rows.push(<ObjectRow/>);
   }
   return rows;
}
<tbody>
{this.row()}  
</tbody>
Rohit Jindal
la source
9

Voici un exemple de doc React: Expressions JavaScript en tant qu'enfants

function Item(props) {
  return <li>{props.message}</li>;
}

function TodoList() {
  const todos = ['finish doc', 'submit pr', 'nag dan to review'];
  return (
    <ul>
      {todos.map((message) => <Item key={message} message={message} />)}
    </ul>
  );
}

comme votre cas, je suggère d'écrire comme ceci:

function render() {
  return (
    <tbody>
      {numrows.map((roe, index) => <ObjectRow key={index} />)}
    </tbody>
  );
}

Veuillez noter que la clé est très importante, car React utilise la clé pour différer les données du tableau.

Sinka Lee
la source
9

Je l'utilise comme

<tbody>
  { numrows ? (
     numrows.map(obj => { return <ObjectRow /> }) 
    ) : null
  }
</tbody>
Sampath
la source
8

Vous pouvez faire quelque chose comme:

let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
Gize Carolina Bonilla Madrazo
la source
8

Grande question.

Ce que je fais quand je veux ajouter un certain nombre de composants, c'est utiliser une fonction d'aide.

Définissez une fonction qui renvoie JSX:

const myExample = () => {
    let myArray = []
    for(let i = 0; i<5;i++) {
        myArray.push(<MyComponent/>)
    }
    return myArray
}

//... in JSX

<tbody>
    {myExample()}
</tbody>
Christophe Pouliot
la source
8

Vous pouvez également utiliser une fonction auto-invoquante:

return <tbody>
           {(() => {
              let row = []
              for (var i = 0; i < numrows; i++) {
                  row.push(<ObjectRow key={i} />)
              }
              return row

           })()}
        </tbody>
Fba Shad
la source
L'utilisation de fonctions anonymes dans le rendu n'est pas considérée comme une bonne pratique pour réagir, car ces fonctions doivent être recréées ou supprimées à chaque nouveau rendu.
Vlatko Vlahek
@VlatkoVlahek vous le confondez avec les accessoires de fonction qui sont recréés à chaque cycle de rendu, ce qui pourrait entraîner de moins bonnes performances à grande échelle. La création d'une fonction anonyme ailleurs n'affectera pas les performances de manière significative.
Emile Bergeron
1
@EmileBergeron C'était il y a un moment haha. Je suis d'accord si ce n'est pas utilisé comme accessoire, il n'y a pas de différence.
Vlatko Vlahek