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?


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/


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


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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.