Rendern von Reaktionskomponenten aus einem Array von Objekten

97

Ich habe einige Daten namens Stationen, die ein Array sind, das Objekte enthält.

stations : [
  {call:'station one',frequency:'000'},
  {call:'station two',frequency:'001'}
]

Ich möchte eine UI-Komponente für jede Array-Position rendern. Soweit kann ich schreiben

 var stationsArr = []
 for (var i = 0; i < this.data.stations.length; i++) {
     stationsArr.push(
         <div className="station">
             {this.data}
         </div>
     )
 }

Und dann rendern

render(){
 return (
   {stationsArr}
 )
}

Das Problem ist, dass ich alle Daten ausdrucken lasse. Ich möchte stattdessen nur einen Schlüssel wie zeigen, {this.data.call}aber das druckt nichts.

Wie kann ich diese Daten durchlaufen und für jede Position des Arrays ein neues UI-Element zurückgeben?

thatgibbyguy
quelle
Ich könnte mich irren, aber ich denke, Sie müssen stationsArranstelle stationsder renderFunktion verwenden.
Tahir Ahmed

Antworten:

149

Sie können die Liste der Stationen ReactElements zuordnen.

Mit React> = 16 ist es möglich, mehrere Elemente von derselben Komponente zurückzugeben, ohne dass ein zusätzlicher HTML-Element-Wrapper erforderlich ist. Seit 16.2 gibt es eine neue Syntax <> zum Erstellen von Fragmenten. Wenn dies nicht funktioniert oder von Ihrer IDE nicht unterstützt wird, können Sie <React.Fragment>stattdessen verwenden. Zwischen 16.0 und 16.2 können Sie eine sehr einfache Polyfüllung für Fragmente verwenden.

Versuche Folgendes

// Modern syntax >= React 16.2.0
const Test = ({stations}) => (
  <>
    {stations.map(station => (
      <div className="station" key={station.call}>{station.call}</div>
    ))}
  </>
); 

// Modern syntax < React 16.2.0
// You need to wrap in an extra element like div here

const Test = ({stations}) => (
  <div>
    {stations.map(station => (
      <div className="station" key={station.call}>{station.call}</div>
    ))}
  </div>
); 

// old syntax
var Test = React.createClass({
    render: function() {
        var stationComponents = this.props.stations.map(function(station) {
            return <div className="station" key={station.call}>{station.call}</div>;
        });
        return <div>{stationComponents}</div>;
    }
});

var stations = [
  {call:'station one',frequency:'000'},
  {call:'station two',frequency:'001'}
]; 

ReactDOM.render(
  <div>
    <Test stations={stations} />
  </div>,
  document.getElementById('container')
);

Vergiss das nicht key Attribut nicht!

https://jsfiddle.net/69z2wepo/14377/

Sebastien Lorber
quelle
@thatgibbyguy: Oh ja! das könnte die richtige Antwort sein. Es muss eine Umhüllung Ihrer untergeordneten Komponenten geben. Ihre renderFunktion muss ein einzelnes Element zurückgeben.
Tahir Ahmed
Was wäre der Grund, ein Schlüsselattribut für jedes Stationselement vorzuschlagen? Ich frage, was würde sich ändern, wenn es jetzt nicht benötigt wird?
Thatgibbyguy
4
@thatgibbyguy in diesem Fall bringt es nicht viel Vorteil. In fortgeschritteneren Beispielen können bessere Renderleistungen erzielt werden, da React leicht erkennen kann, ob ein vorhandener Knoten an einen anderen Ort im Stationsarray verschoben wurde, wodurch vermieden wird, dass ein vorhandener Dom-Knoten zerstört und neu erstellt wird (und der Dom-Knoten auch weiterhin bereitgestellt bleibt). . Es ist in der Reaktion doc: facebook.github.io/react/docs/reconciliation.html#keys
Sebastien Lorber
Etwas abseits des Themas, aber ich bin mir nicht sicher, wie ich eine Abfrage erstellen soll, um dies zu fragen. Wie würde man bei Verwendung der ES6-Syntax in Ihrem obigen Beispiel vorgehen, um den Index von der Karte zu übergeben? IOW, wie kann ich herausfinden, ob ich mich im letzten Knoten des Arrays befinde? Ich habe versucht, mich in Parens zu wickeln, und das schien nicht gut zu gehen.
Lane Goolsby
@ ElHombre stations.map((station,index) => { })funktioniert gut für mich
Sebastien Lorber
45

Ich habe eine Antwort, die für Neulinge wie mich etwas weniger verwirrend sein könnte. Sie können nur mapinnerhalb der Komponenten-Render-Methode verwenden.

render () {
   return (
       <div>
           {stations.map(station => <div key={station}> {station} </div>)} 
       </div>
   );
}
Thomas Valadez
quelle
11
Dies erfordert eine keyRequisite reactjs.org/docs/lists-and-keys.html#keys
David Barratt
1
Manchmal ist das viel hilfreicher. :)
ferit
6

this.data enthält vermutlich alle Daten, also müssten Sie so etwas tun:

var stations = [];
var stationData = this.data.stations;

for (var i = 0; i < stationData.length; i++) {
    stations.push(
        <div key={stationData[i].call} className="station">
            Call: {stationData[i].call}, Freq: {stationData[i].frequency}
        </div>
    )
}

render() {
  return (
    <div className="stations">{stations}</div>
  )
}

Oder Sie können mapund Pfeilfunktionen verwenden, wenn Sie ES6 verwenden:

const stations = this.data.stations.map(station =>
    <div key={station.call} className="station">
      Call: {station.call}, Freq: {station.frequency}
    </div>
);
Dominic
quelle
2
Dies funktioniert in der aktuellen React-Version nicht. Sie können kein Array zurückgeben.
Aftab Naveed
@AftabNaveed danke Ich habe es aktualisiert, Render sollte ein Element zurückgeben, aber es ist gültig, ein Array von Elementen darin zu haben
Dominic
Wie @AftabNaveed sagt, wenn Sie Version <16 reagieren, müssen Sie oben verwenden, sonst können Sie nur return stations;( codepen.io/pawelgrzybek/pen/WZEKWj )
Hühnersuppe
1

Es gibt verschiedene Möglichkeiten.

const stations = [
  {call:'station one',frequency:'000'},
  {call:'station two',frequency:'001'}
];
const callList = stations.map(({call}) => call)

Lösung 1

<p>{callList.join(', ')}</p>

Lösung 2

<ol>    
  { callList && callList.map(item => <li>{item}</li>) }
</ol>

Bearbeiten Sie kind-antonelli-z8372

Natürlich gibt es auch andere Möglichkeiten.

Mo.
quelle