Rendering di componenti React da array di oggetti


98

Ho alcuni dati chiamati stazioni che sono un array contenente oggetti.

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

Vorrei eseguire il rendering di un componente dell'interfaccia utente per ogni posizione dell'array. Finora posso scrivere

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

E poi renderizza

render(){
 return (
   {stationsArr}
 )
}

Il problema è che sto stampando tutti i dati. Invece voglio solo mostrare una chiave come {this.data.call}ma che non stampa nulla.

Come posso scorrere questi dati e restituire un nuovo elemento dell'interfaccia utente per ogni posizione dell'array?


Potrei sbagliarmi ma penso che tu debba usare stationsArrinvece che stationsall'interno della renderfunzione.
Tahir Ahmed

Risposte:


151

Puoi mappare l'elenco delle stazioni su ReactElements.

Con React> = 16, è possibile restituire più elementi dallo stesso componente senza bisogno di un wrapper di elemento html aggiuntivo. Dalla 16.2, c'è una nuova sintassi <> per creare frammenti. Se questo non funziona o non è supportato dal tuo IDE, puoi usare <React.Fragment>invece. Tra 16.0 e 16.2, puoi usare un polyfill molto semplice per i frammenti.

Prova quanto segue

// 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')
);

Non dimenticare l' keyattributo!

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


@thatgibbyguy: Oh sì! potrebbe essere la risposta giusta. Ci deve essere un avvolgimento attorno ai componenti del bambino. La tua renderfunzione deve restituire un singolo elemento.
Tahir Ahmed

Quale sarebbe la ragione per suggerire un attributo chiave per ogni elemento della stazione? Quello che sto chiedendo è: cosa cambierebbe se non fosse necessario ora?
thatgibbyguy

4
@thatgibbyguy in questo caso non porta molto vantaggio. Negli esempi più avanzati permette di avere prestazioni di rendering migliori in quanto React può facilmente sapere se un nodo esistente è stato spostato in un altro posto nell'array della stazione, evitando così di distruggere e ricreare un nodo dom esistente (e anche mantenere il nodo dom montato) . È nel documento di reazione: facebook.github.io/react/docs/reconciliation.html#keys
Sebastien Lorber

Un po 'fuori tema ma non sono sicuro di come costruire una query per chiedere questo. Quando si utilizza la sintassi ES6 nell'esempio sopra, come si passerebbe l'indice dalla mappa? IOW, come posso capire se sono nell'ultimo nodo dell'array? Ho provato a fare il wrapping tra parentesi e non sembrava andare bene.
Lane Goolsby

@ElHombre stations.map((station,index) => { })funziona bene per me
Sebastien Lorber

46

Ho una risposta che potrebbe essere un po 'meno confusa per i neofiti come me. Puoi semplicemente usare mapall'interno del metodo di rendering dei componenti.

render () {
   return (
       <div>
           {stations.map(station => <div key={station}> {station} </div>)} 
       </div>
   );
}

11
Questo ha bisogno di un keyprop reactjs.org/docs/lists-and-keys.html#keys
David Barratt

1
A volte questo è molto più utile. :)
Ferit

6

this.data presumibilmente contiene tutti i dati, quindi dovresti fare qualcosa del genere:

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

Oppure puoi usare mape le funzioni freccia se stai usando ES6:

const stations = this.data.stations.map(station =>
    <div key={station.call} className="station">
      Call: {station.call}, Freq: {station.frequency}
    </div>
);

2
Questo non funzionerà nell'attuale versione di React, non puoi restituire un array.
Aftab Naveed

@AftabNaveed grazie l'ho aggiornato, il rendering dovrebbe restituire un elemento ma è valido avere un array di elementi al suo interno
Dominic

Come dice @AftabNaveed, se la versione di reazione <16, dovrai usare sopra, altrimenti puoi semplicemente return stations;( codepen.io/pawelgrzybek/pen/WZEKWj )
Zuppa di pollo

1

Ci sono un paio di modi che possono essere usati.

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

Soluzione 1

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

Soluzione 2

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

Modifica kind-antonelli-z8372

Naturalmente ci sono anche altri modi disponibili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.