Renderowanie komponentów reagujących z tablicy obiektów

105

Mam pewne dane zwane stacjami, które są tablicą zawierającą obiekty.

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

Chciałbym wyrenderować składnik interfejsu użytkownika dla każdej pozycji tablicy. Póki co mogę pisać

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

A następnie renderuj

render(){
 return (
   {stationsArr}
 )
}

Problem w tym, że wszystkie dane są drukowane. Zamiast tego chcę po prostu pokazać klucz w stylu, {this.data.call}który nic nie drukuje.

Jak mogę przejrzeć te dane i zwrócić nowy element interfejsu użytkownika dla każdej pozycji tablicy?

thatgibbyguy
źródło
Mogę się mylić, ale myślę, że musisz użyć stationsArrzamiast stationswewnątrz renderfunkcji.
Tahir Ahmed

Odpowiedzi:

155

Możesz zmapować listę stacji do ReactElements.

Z React> = 16, możliwe jest zwrócenie wielu elementów z tego samego komponentu bez potrzeby dodatkowego opakowania elementu HTML. Od 16.2 dostępna jest nowa składnia <> do tworzenia fragmentów. Jeśli to nie działa lub nie jest obsługiwane przez IDE, możesz użyć <React.Fragment>zamiast tego. Między 16.0 a 16.2 możesz użyć bardzo prostego wypełnienia dla fragmentów.

Spróbuj wykonać następujące czynności

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

Nie zapomnij o keyatrybucie!

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

Sebastien Lorber
źródło
@thatgibbyguy: O tak! to może być właściwa odpowiedź. Wokół komponentów podrzędnych musi być zawijanie. Twoja renderfunkcja musi zwracać jeden element.
Tahir Ahmed
Jaki byłby powód sugerowania kluczowego atrybutu dla każdego elementu stacji? Pytam, co by to zmieniło, gdyby nie było teraz potrzebne?
thatgibbyguy
4
@thatgibbyguy w tym przypadku nie przynosi wiele korzyści. W bardziej zaawansowanych przykładach pozwala uzyskać lepszą wydajność renderowania, ponieważ React może z łatwością wiedzieć, czy istniejący węzeł został przeniesiony w inne miejsce w szyku stacji, unikając w ten sposób zniszczenia i odtworzenia istniejącego węzła dom (a także utrzymania zamontowanego węzła dom) . Jest w dokumencie react: facebook.github.io/react/docs/reconciliation.html#keys
Sebastien Lorber
Trochę poza tematem, ale nie jestem pewien, jak skonstruować zapytanie, aby o to zapytać. Korzystając ze składni ES6 w powyższym przykładzie, jak można by przekazać indeks z mapy? IOW, jak mogę się dowiedzieć, czy jestem w ostatnim węźle tablicy? Próbowałem zawinąć w pareny i nie wyglądało to dobrze.
Lane Goolsby
@ElHombre stations.map((station,index) => { })działa dobrze dla mnie
Sebastien Lorber,
49

Mam odpowiedź, która może być nieco mniej myląca dla początkujących, takich jak ja. Możesz po prostu użyć mapw ramach metody renderowania komponentów.

render () {
   return (
       <div>
           {stations.map(station => <div key={station}> {station} </div>)} 
       </div>
   );
}
Thomas Valadez
źródło
11
To wymaga keyrekwizytu actjs.org/docs/lists-and-keys.html#keys
David Barratt
2
Czasami jest to znacznie bardziej pomocne. :)
Ferit
7

this.data prawdopodobnie zawiera wszystkie dane, więc musiałbyś zrobić coś takiego:

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

Lub możesz użyć mapfunkcji i strzałek, jeśli używasz ES6:

const stations = this.data.stations.map(station =>
    <div key={station.call} className="station">
      Call: {station.call}, Freq: {station.frequency}
    </div>
);
Dominic
źródło
2
To nie zadziała w aktualnej wersji Reacta, nie możesz zwrócić tablicy.
Aftab Naveed
@AftabNaveed dzięki zaktualizowałem to, renderowanie powinno zwrócić jeden element, ale ważne jest, aby mieć w nim tablicę elementów
Dominic
Jak mówi @AftabNaveed, jeśli zareagujesz w wersji <16, będziesz musiał użyć powyższego, w przeciwnym razie możesz po prostu return stations;( codepen.io/pawelgrzybek/pen/WZEKWj )
Chicken Suop
1

Istnieje kilka sposobów, z których można skorzystać.

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

Rozwiązanie 1

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

Rozwiązanie 2

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

Edytuj kind-antonelli-z8372

Oczywiście dostępne są również inne sposoby.

Pon.
źródło