Schleife in React JSX

1278

Ich versuche in React JSX(wobei ObjectRow eine separate Komponente ist) Folgendes zu tun :

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

Ich erkenne und verstehe, warum dies nicht gültig ist JSX, da JSXes Funktionsaufrufen zugeordnet ist. Da JSXich jedoch aus dem Vorlagenland komme und neu in diesem Bereich bin, bin ich mir nicht sicher, wie ich das oben genannte erreichen würde (mehrmaliges Hinzufügen einer Komponente).

Ben Roberts
quelle
38
Es ist wichtig zu beachten, dass Sie in JSX die {} -Tags um Ihre JavaScript-Syntax benötigen. Dies kann facebook.github.io/react/docs/… helfen .
Jesaja Grau
30
let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
OverCoder
@OverCoder warum würdest du die gesamte Rückgabe in das {} -Tag einfügen, das wäre => return <h1> {todo.title} </ h1> Ist es nicht so?
Pravin Poudel
1
@pravinpoudel eigentlich ist diese Antwort alt, eher wie let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

Antworten:

1205

Stellen Sie sich vor, Sie rufen nur JavaScript-Funktionen auf. Sie können keine forSchleife verwenden, in die die Argumente für einen Funktionsaufruf gehen würden:

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

Sehen Sie, wie der Funktion tbodyeine forSchleife als Argument übergeben wird, und das ist natürlich ein Syntaxfehler.

Sie können jedoch ein Array erstellen und dieses dann als Argument übergeben:

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

Bei der Arbeit mit JSX können Sie grundsätzlich dieselbe Struktur verwenden:

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

Übrigens ist mein JavaScript-Beispiel fast genau das, in das sich dieses Beispiel von JSX verwandelt. Spielen Sie mit Babel REPL , um ein Gefühl dafür zu bekommen, wie JSX funktioniert.

Sophie Alpert
quelle
3
Es ist möglich, dass sich der Compiler geändert hat, da dieses Beispiel im jsx-Compiler nicht zu kompilieren scheint , aber die Verwendung von map wie in der Antwort von FakeRainBrigand unten scheint korrekt zu kompilieren.
Rav
9
Ich kann versprechen, dass das letzte Beispiel auf dem neuesten JSX-Compiler immer noch korrekt kompiliert wird.
Sophie Alpert
3
Das funktioniert gut. Die Antwort von FakeRainBrigand funktioniert für eine einfache Array-Iteration. Diese Antwort ist jedoch ein Muss für Szenarien, in denen Sie sie nicht verwenden können map(z. B. wenn keine Sammlung in einer Variablen gespeichert ist).
Kelvin
52
React muss dom effizient aktualisieren. In diesem Fall sollte der Elternteil keyjedem Kind ein a zuweisen. REF: facebook.github.io/react/docs/…
qsun
7
Dieses Beispiel wird funktionieren, aber es fehlen einige wichtige Elemente wie die keyEigenschaft und auch ein Codestil, der in React-Codebasen nicht wirklich verwendet wird. Bitte betrachten Sie diese Antwort auf stackoverflow.com/questions/22876978/loop-inside-react-jsx/… als richtig.
okonetchnikov
866

Ich bin mir nicht sicher, ob dies für Ihre Situation funktioniert, aber oft ist die Karte eine gute Antwort.

Wenn dies Ihr Code mit der for-Schleife war:

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

Sie könnten es so mit Karte schreiben :

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

ES6-Syntax:

<tbody>
    {objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
Räuber
quelle
43
Map ist sinnvoller, wenn der Iteratee ein Array ist. Eine for-Schleife ist geeignet, wenn es sich um eine Zahl handelt.
Code Whisperer
26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>mit Reactify ES6-Unterstützung oder Babel.
Distortum
3
+1. Ich benutze dies sogar mit einer ul (ungeordnete Liste). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>mit TypeScript
Roberto C Navarro
5
Das ist großartig, aber Sie können kein Objekt abbilden. Dafür würde ich verwendenfor..in
Damon
4
Beachten Sie, dass die Reihenfolge der Schlüssel bei Verwendung von Object.keys beliebig ist. Ich finde, dass das separate Speichern der Reihenfolge der Schlüssel gut funktioniert, und bei Bedarf auch die Reihenfolge im Objektliteral. Das erlaubt mir, Code wiethis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr
443

Wenn Sie noch kein Array haben, map()das die Antwort von @ FakeRainBrigand mag, und dies einbinden möchten, damit das Quelllayout der Ausgabe entspricht, die näher an der Antwort von @ SophieAlpert liegt:

Mit ES2015 (ES6) Syntax (Spread- und Pfeilfunktionen)

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

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

Betreff: Transpilieren mit Babel, seine Vorbehaltsseite besagt, dass Array.fromdies für die Verbreitung erforderlich ist, aber derzeit ( v5.8.23) scheint dies beim Verbreiten eines tatsächlichen nicht der Fall zu sein Array. Ich habe ein Dokumentationsproblem offen, um dies zu klären. Die Verwendung erfolgt jedoch auf eigenes Risiko oder durch 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>

Kombination von Techniken aus anderen Antworten

Behalten Sie das Quelllayout bei, das der Ausgabe entspricht, aber machen Sie den Inline-Teil kompakter:

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

Mit ES2015 Syntax & ArrayMethoden

Mit können Array.prototype.fillSie dies als Alternative zur Verwendung von Spread wie oben dargestellt tun:

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

(Ich denke, Sie könnten tatsächlich jedes Argument weglassen fill(), aber ich bin nicht zu 100% damit einverstanden.) Vielen Dank an @FakeRainBrigand für die Korrektur meines Fehlers in einer früheren Version der fill()Lösung (siehe Überarbeitungen).

key

In allen Fällen keyverringert der attr eine Warnung beim Build der Entwicklung, ist jedoch für das Kind nicht zugänglich. Sie können ein zusätzliches Attribut übergeben, wenn der Index im untergeordneten Element verfügbar sein soll. Siehe Listen und Schlüssel zur Diskussion.

JMM
quelle
2
Was ist mit yield? Das Verschieben von Elementen in ein Zwischenarray ist etwas hässlich, wenn wir Generatoren haben. Arbeiten Sie?
Mpen
2
@ Mark Ich weiß nicht, dass Generatoren hier wirklich anwendbar sind. Der Schlüssel dazu im Kontext von JSX ist ein Ausdruck, der ein Array zurückgibt. Wenn Sie also einen Generator verwenden würden, würden Sie ihn wahrscheinlich trotzdem verbreiten, und er wäre wahrscheinlich ausführlicher als die ES2015-basierten Lösungen hier.
JMM
2
Wie ist das ausführlicher? Und warum sollte JSX keine iterierbaren Arrays akzeptieren, nicht nur Arrays?
Mpen
2
@Mark Das ist zwar weniger ausführlich als das von mir verwendete (ES5) IIFE-Beispiel, aber es ist wesentlich ausführlicher als die [...Array(x)].map(() => <El />))Version, die ich für die eleganteste halte und warum ich sie vorgestellt habe. Betreff: Die zweite Frage, das ist ein großartiger Punkt. Es scheint nichts an JSX zu geben, was dies ausschließt, daher hängt es davon ab, was React oder ein anderer Konsument von transformiertem JSX mit den untergeordneten Argumenten macht, was ich nicht sagen kann, ohne auf die Quelle zu schauen. Wissen Sie? Es ist eine faszinierende Frage.
JMM
3
@corysimmons Cool, danke für die Infos zu fill(). Ich erinnere mich jetzt, dass der Grund, warum ich gezögert habe, eine Frage ist, wie die Optionalität von Parametern in der ES-Spezifikation angegeben ist (muss dies irgendwann prüfen). Das Komma ist nur eine Möglichkeit, ein Array-Element zu entfernen - in diesem Fall das erste. Sie können dies tun, wenn die Indizes von 1..Länge des Arrays stammen sollen, das Sie verbreiten, und nicht von 0..Länge-1 des gespreizten Arrays (weil elidierte Elemente nur zur Länge des Arrays beitragen und nicht '). keine entsprechende Eigenschaft haben).
JMM
85

Verwenden Sie einfach die map Array- Methode mit ES6-Syntax:

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

Vergessen Sie nicht die keyEigenschaft.

danielfeelfine
quelle
Ich füge einen zufälligen 'Math.random ()' Schlüssel anstelle von id hinzu. Es funktioniert nicht gut, wenn setState in Kindern verwendet wird. Haben Sie eine Idee warum?
Oliver D
82

Mit Array Kartenfunktion Schleife durch eine sehr gängige Methode ist Array von Elementen und schaffen Komponenten nach ihnen in React , ist dies eine gute Möglichkeit , um eine Schleife zu tun , was recht effizient und ordentlich Weg, um Ihre Schleifen zu tun JSX , es ist nicht die einzig Weg, es zu tun, aber der bevorzugte Weg.

Vergessen Sie auch nicht, für jede Iteration nach Bedarf einen eindeutigen Schlüssel zu haben. Die Kartenfunktion erstellt einen eindeutigen Index aus 0, es wird jedoch nicht empfohlen, den erstellten Index zu verwenden. Wenn Ihr Wert jedoch eindeutig ist oder ein eindeutiger Schlüssel vorhanden ist, können Sie diese verwenden:

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

Außerdem einige Zeilen aus MDN, wenn Sie mit der Kartenfunktion auf Array nicht vertraut sind:

map ruft eine bereitgestellte Rückruffunktion einmal für jedes Element in einem Array der Reihe nach auf und erstellt aus den Ergebnissen ein neues Array. Der Rückruf wird nur für Indizes des Arrays aufgerufen, denen Werte zugewiesen wurden, einschließlich undefinierter. Es wird nicht für fehlende Elemente des Arrays aufgerufen (dh Indizes, die nie festgelegt wurden, die gelöscht wurden oder denen noch nie ein Wert zugewiesen wurde).

Der Rückruf wird mit drei Argumenten aufgerufen: dem Wert des Elements, dem Index des Elements und dem Array-Objekt, das durchlaufen wird.

Wenn ein thisArg-Parameter zum Zuordnen bereitgestellt wird, wird er als Rückruf für diesen Wert verwendet. Andernfalls wird der undefinierte Wert als dieser Wert verwendet. Dieser Wert, der letztendlich vom Rückruf beobachtet werden kann, wird gemäß den üblichen Regeln zum Bestimmen des von einer Funktion gesehenen Werts bestimmt.

map mutiert nicht das Array, auf dem es aufgerufen wird (obwohl ein Rückruf, wenn er aufgerufen wird, dies tun kann).

Alireza
quelle
Array#mapist nicht asynchron!
Philraj
52

Wenn Sie bereits lodash verwenden, ist die _.timesFunktion praktisch.

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
quelle
1
Array.prototype.map kann hier eine gute Option sein, wenn Sie keine Bibliothek wie lodash einschließen. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Jesaja Grau
1
@IsaiahGrey Nur wenn Sie bereits ein Array haben. Manchmal möchte man Dinge nur ein paar Mal wiederholen.
Mpen
1
Natürlich! Viele verschiedene Ansätze, abhängig von den tatsächlichen Daten. Ich habe festgestellt, dass wir in unserem Entwicklungsprozess häufig in der Lage waren, die Karte anzupassen, da die Daten modelliert wurden. Tolles Beispiel mit lodash! Übrigens, verwenden Sie die Eigenschaftsinitialisierersyntax, um Ihre Methoden an Ihre Komponenten zu binden?
Jesaja Grau
4
@IsaiahGrey Ich denke, sie heißen nur ES6- Methodendefinitionen
mpen
41

Sie können auch außerhalb des Rückgabeblocks extrahieren:

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

    return (<tbody>{rows}</tbody>);
}
Brandon Sibeitokgong
quelle
34

Ich weiß, dass dies ein alter Thread ist, aber vielleicht möchten Sie React Templates auschecken auschecken, mit dem Sie Vorlagen in jsx-Stil mit einigen Anweisungen (z. B. rt-repeat) als Reaktion verwenden können.

Ihr Beispiel wäre, wenn Sie Reaktionsvorlagen verwenden würden:

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>
Etai
quelle
Warum wird eine zusätzliche Bibliothek verwendet, während einfaches Javascript bereits eine Lösung mit verschiedenen for-Schleifen- oder Array.prototype.map-Methoden zur Lösung des Problems bereitgestellt hat? Ich selbst habe in meinem aktuellen Projekt bereits beide einfachen Javascript-Methoden verwendet, die gut funktionieren. Die Gewohnheit, wenn immer möglich einfache Javascript-Methoden zu verwenden, hilft mir, meine Fähigkeiten in Javascript zu verbessern. Ich verwende zusätzliche Bibliotheken nur, wenn es schwierig zu sein scheint, Lösungen für bestimmte Probleme zu finden, z. B. das Routing mit React-Router.
Lex Soft
27

Es gibt mehrere Möglichkeiten, dies zu tun. JSX wird schließlich zu JavaScript kompiliert. Solange Sie gültiges JavaScript schreiben, sind Sie gut.

Meine Antwort zielt darauf ab, all die wunderbaren Möglichkeiten zu konsolidieren, die hier bereits vorgestellt wurden:

Wenn Sie kein Array von Objekten haben, geben Sie einfach die Anzahl der Zeilen an:

innerhalb des returnBlocks erstellen Arrayund verwenden Array.prototype.map:

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

returnVerwenden Sie außerhalb des Blocks einfach eine normale JavaScript-for-Schleife:

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

sofort aufgerufener Funktionsausdruck:

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

Wenn Sie ein Array von Objekten haben

Innerhalb des returnBlocks .map()jedes Objekt einer <ObjectRow>Komponente:

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

returnVerwenden Sie außerhalb des Blocks einfach eine normale JavaScript-for-Schleife:

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

sofort aufgerufener Funktionsausdruck:

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
quelle
2
Tolle Antworten: Verschiedene Techniken, alle verwenden nur einfaches Javascript, das die Leistungsfähigkeit von Javascript zeigt, dank seiner verschiedenen Möglichkeiten, ähnliche Aufgaben zu erledigen.
Lex Soft
24

Wenn numrows ein Array ist und es sehr einfach ist.

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

Der Array-Datentyp in React ist sehr viel besser, das Array kann ein neues Array unterstützen und Filter, Reduzieren usw. unterstützen.

Lulin
quelle
Dies ist keine anständige Antwort, da kein Schlüssel verwendet wird.
Kojow7
21

Es gibt mehrere Antworten, die auf die Verwendung der mapAnweisung hinweisen . Hier ist ein vollständiges Beispiel für die Verwendung eines Iterators in der FeatureList- Komponente zum Auflisten von Feature- Komponenten basierend auf einer JSON-Datenstruktur namens 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>
); 

Sie können den vollständigen FeatureList-Code auf GitHub anzeigen . Das Feature-Fixture ist hier aufgelistet .

Manav Sehgal
quelle
Beim Umgang mit JSON-Daten, z. B. beim Abrufen von Daten aus der Datenbank mithilfe der Fetch-API, verwende ich die Methode Array.prototype.map. Dies ist ein bequemer und bewährter Weg.
Lex Soft
17

Um mehrmals zu schleifen und zurückzukehren, können Sie dies mit Hilfe von fromund erreichen map:

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

wo i = number of times


Wenn Sie den gerenderten Komponenten eindeutige Schlüssel-IDs zuweisen möchten, können Sie diese React.Children.toArraywie in der React-Dokumentation vorgeschlagen verwenden

React.Children.toArray

Gibt die undurchsichtige Datenstruktur der Kinder als flaches Array mit den jedem Kind zugewiesenen Schlüsseln zurück. Nützlich, wenn Sie Sammlungen von untergeordneten Elementen in Ihren Rendermethoden bearbeiten möchten, insbesondere, wenn Sie this.props.children neu anordnen oder in Scheiben schneiden möchten, bevor Sie es weitergeben.

Hinweis:

React.Children.toArray()Ändert die Schlüssel, um die Semantik verschachtelter Arrays beim Reduzieren von untergeordneten Listen beizubehalten. Das heißt, toArray stellt jedem Schlüssel im zurückgegebenen Array ein Präfix vor, sodass der Schlüssel jedes Elements auf das Eingabearray beschränkt ist, das ihn enthält.

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

Wenn Sie sich für die Konvertierung dieser Methode return () der Rendermethode entscheiden , ist die Verwendung der Methode map () die einfachste Option . Ordnen Sie Ihr Array mit der Funktion map () der JSX-Syntax zu (siehe unten) ( ES6-Syntax wird verwendet ).


Innerhalb der übergeordneten Komponente :

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

Bitte beachten Sie das keyAttribut, das Ihrer untergeordneten Komponente hinzugefügt wurde. Wenn Sie kein Schlüsselattribut angegeben haben, wird auf Ihrer Konsole die folgende Warnung angezeigt.

Warnung: Jedes Kind in einem Array oder Iterator sollte eine eindeutige "Schlüssel" -Stütze haben.

Hinweis: Ein häufiger Fehler besteht darin, indexbeim Iterieren als Schlüssel zu verwenden. Die Verwendung indexdes Elements als Schlüssel ist ein Anti-Pattern. Weitere Informationen hierzu finden Sie hier . Kurz gesagt, wenn es sich NICHT um eine statische Liste handelt, verwenden Sie sie niemals indexals Schlüssel.


Jetzt bei der ObjectRow Komponente über ihre Eigenschaften auf das Objekt zugreifen.

Innerhalb der ObjectRow-Komponente

const { object } = this.props

oder

const object = this.props.object

Dadurch sollten Sie das Objekt abrufen, das Sie von der übergeordneten Komponente an die Variable objectin der ObjectRow- Komponente übergeben haben. Jetzt können Sie die Werte in diesem Objekt entsprechend Ihrem Zweck ausspucken.


Verweise :

map () -Methode in Javascript

ECMA Script 6 oder ES6

Bharadhwaj
quelle
16

Nehmen wir an, wir haben eine Reihe von Artikeln in Ihrem Bundesstaat:

[{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
quelle
Ich denke, Sie müssen möglicherweise das {} nach der Karte (Element) loswerden, das schien für mich zu funktionieren.
Ian
15

Eine ES2015 / Babel-Möglichkeit verwendet eine Generatorfunktion, um ein Array von JSX zu erstellen:

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
quelle
15

... oder Sie können auch ein Array von Objekten vorbereiten und einer Funktion zuordnen, um die gewünschte Ausgabe zu erhalten. Ich bevorzuge dies, weil es mir hilft, die bewährte Codierungspraxis ohne Logik bei der Rückgabe von Render beizubehalten.

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
quelle
15

Verwenden Sie einfach, .map()um Ihre Sammlung zu durchlaufen und <ObjectRow>Gegenstände mit Requisiten aus jeder Iteration zurückzugeben.

Angenommen, objectsirgendwo ist ein Array ...

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

ES2015 Array.from mit der Kartenfunktion + Taste

Wenn Sie nichts zu tun haben, können .map()Sie Array.from()mit der mapFunktion Elemente wiederholen:

<tbody>
  {Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>
Asynchronisieren
quelle
15

Ich benutze das:

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

PS: Vergiss niemals den Schlüssel, sonst wirst du viele Warnungen haben!

JC
quelle
Oder verwenden Sie den Array-Index, wenn Ihre Elemente keine .IdEigenschaft haben, wieitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur
13

Ich tendiere dazu, einen Ansatz zu bevorzugen, bei dem die Programmierlogik außerhalb des Rückgabewerts von erfolgt render . Dies hilft dabei, das, was tatsächlich gemacht wird, leicht zu groken.

Also würde ich wahrscheinlich so etwas machen wie:

import _ from 'lodash';

...

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

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

Zugegeben, dies ist eine so kleine Menge an Code, dass das Inlining möglicherweise gut funktioniert.

Adam Donahue
quelle
Großer Fan von lodash map zum Durchlaufen von Objekten. Ich würde gerne dazu neigen, import { map } from 'lodash'dass Sie nicht alle Lodash-Funktionen importieren, wenn Sie sie jedoch nicht benötigen.
Stretch0
Heutzutage brauchen wir nicht einmal eine Lodash-Karte - kartieren Sie einfach direkt über das Array.
Adam Donahue
Ja, aber Sie können mit es6 kein Objekt durchlaufen map(), sondern nur Arrays. Das habe ich gesagt, Lodash ist gut, um ein Objekt zu durchlaufen.
Stretch0
Ich dachte du meinst objectswie in einer Liste von Dingen meinen Fehler.
Adam Donahue
12

Sie können natürlich mit einer .map lösen, wie in der anderen Antwort vorgeschlagen. Wenn Sie babel bereits verwenden, können Sie über die Verwendung von jsx-control-Anweisungen nachdenken. Sie erfordern ein wenig Einstellung, aber ich denke, es lohnt sich in Bezug auf die Lesbarkeit (insbesondere für nicht reagierende Entwickler). Wenn Sie einen Linter verwenden, gibt es auch eslint-plugin-jsx-control-Anweisungen

Jurgo Boemo
quelle
12

Ihr JSX-Code wird in reinen JavaScript-Code kompiliert, alle Tags werden durch ReactElementObjekte ersetzt. In JavaScript können Sie eine Funktion nicht mehrmals aufrufen, um die zurückgegebenen Variablen zu erfassen.

Es ist illegal, die einzige Möglichkeit besteht darin, ein Array zum Speichern der von der Funktion zurückgegebenen Variablen zu verwenden.

Oder Sie können verwenden, Array.prototype.mapwas seit JavaScript ES5 verfügbar ist , um diese Situation zu behandeln.

Vielleicht können wir einen anderen Compiler schreiben, um eine neue JSX-Syntax neu zu erstellen und eine Wiederholungsfunktion wie die von Angularng-repeat zu implementieren .

hlissnake
quelle
12

Dies kann auf verschiedene Arten erfolgen.

  1. Wie oben vorgeschlagen, bevor Sie returnalle Elemente im Array speichern
  2. Schleife hinein return

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

    Methode 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
quelle
Ja. In meinem aktuellen Projekt verwende ich Methode 1, dh die Methode Array.prototype, forEach (), um ein HTML-Auswahlelement zu erstellen, das mit Daten aus der Datenbank gefüllt ist. Ich werde sie jedoch eher durch die Array.prototype.map () -Methode ersetzen, da die Map-Methode kompakter aussieht (weniger Code).
Lex Soft
10

Hier ist eine einfache Lösung dafür.

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

Keine Zuordnung und kein komplexer Code erforderlich. Sie müssen nur die Zeilen in das Array verschieben und die Werte zurückgeben, um es zu rendern.

Javasamurai
quelle
Beim Erstellen eines HTML-Auswahlelements kam mir diese ähnliche Technik zuerst in den Sinn. Also habe ich sie verwendet, obwohl ich die forEach () -Methode verwende. Beim erneuten Lesen des React-Dokuments zu Themen mit Listen und Schlüsseln stellte ich jedoch fest, dass sie die map () -Methode verwenden, wie auch in mehreren Antworten hier gezeigt. Dies lässt mich denken, dass dies der bevorzugte Weg ist. Ich stimme zu, da es kompakter aussieht (weniger Code).
Lex Soft
9

Da Sie Javascript-Syntax in JSX-Code schreiben, müssen Sie Ihr Javascript in geschweifte Klammern setzen.

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

Hier ist ein Beispiel aus React doc: JavaScript-Ausdrücke als untergeordnete Elemente

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

Als Ihren Fall schlage ich vor, wie folgt zu schreiben:

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

Bitte beachten Sie, dass der Schlüssel sehr wichtig ist, da React use Key verwendet, um Daten im Array zu unterscheiden.

Sinka Lee
quelle
9

Ich benutze es gerne

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

Sie können so etwas tun wie:

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

Gute Frage.

Wenn ich eine bestimmte Anzahl von Komponenten hinzufügen möchte, verwende ich eine Hilfsfunktion.

Definieren Sie eine Funktion, die JSX zurückgibt:

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

//... in JSX

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

Sie können auch eine selbstaufrufende Funktion verwenden:

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

           })()}
        </tbody>
Fba Shad
quelle
Die Verwendung anonymer Funktionen innerhalb des Renderns wird beim Reagieren nicht als bewährte Methode angesehen, da diese Funktionen bei jedem erneuten Rendern neu erstellt oder verworfen werden müssen.
Vlatko Vlahek
@VlatkoVlahek Sie verkennen es mit Funktion Requisiten sind neu erstellt jeden Zyklus machen, das könnte zu einer schlechteren Leistung in großem Umfang führen. Das Erstellen anonymer Funktionen an anderen Orten hat keinen wesentlichen Einfluss auf die Leistung.
Emile Bergeron
1
@EmileBergeron Das ist eine Weile her haha. Ich stimme zu, wenn dies nicht als Requisite verwendet wird, gibt es keinen Unterschied.
Vlatko Vlahek