Renderizando Componentes React a partir de Matriz de Objetos


98

Eu tenho alguns dados chamados de estações que são uma matriz que contém objetos.

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

Eu gostaria de renderizar um componente de interface do usuário para cada posição da matriz. Até agora eu posso escrever

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

E então renderizar

render(){
 return (
   {stationsArr}
 )
}

O problema é que estou imprimindo todos os dados. Em vez disso, quero apenas mostrar uma chave como, {this.data.call}mas não imprime nada.

Como posso fazer um loop por esses dados e retornar um novo elemento de interface do usuário para cada posição da matriz?


Posso estar errado, mas acho que você precisa usar em stationsArrvez de stationsdentro da renderfunção.
Tahir Ahmed

Respostas:


151

Você pode mapear a lista de estações para ReactElements.

Com React> = 16, é possível retornar vários elementos do mesmo componente sem a necessidade de um wrapper de elemento html extra. Desde 16.2, existe uma nova sintaxe <> para criar fragmentos. Se isso não funcionar ou não for suportado por seu IDE, você pode usar <React.Fragment>. Entre 16.0 e 16.2, você pode usar um polyfill muito simples para fragmentos.

Tente o seguinte

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

Não se esqueça do keyatributo!

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


@thatgibbyguy: Oh sim! essa pode ser a resposta certa. É necessário que haja um envolvimento em torno de seus componentes filhos. Sua renderfunção deve retornar um único elemento.
Tahir Ahmed

Qual seria a razão para sugerir um atributo-chave para cada elemento da estação? O que estou perguntando é: o que mudaria se não fosse necessário agora?
thatgibbyguy

4
@thatgibbyguy nesse caso não traz muita vantagem. Em exemplos mais avançados, permite ter um melhor desempenho de renderização, pois o React pode facilmente saber se um nó existente foi movido para outro lugar na matriz da estação, evitando assim destruir e recriar um nó dom existente (e também manter o nó dom montado) . Está no documento de reação: facebook.github.io/react/docs/reconciliation.html#keys
Sebastien Lorber

Um pouco fora do tópico, mas não tenho certeza de como construir uma consulta para fazer isso. Ao usar a sintaxe ES6 em seu exemplo acima, como alguém faria para passar o índice do mapa? IOW, como posso saber se estou no último nó da matriz? Tentei embrulhar em parênteses e não pareceu correr bem.
Lane Goolsby

@ElHombre stations.map((station,index) => { })funciona bem para mim
Sebastien Lorber

46

Tenho uma resposta que pode ser um pouco menos confusa para iniciantes como eu. Você pode apenas usar mapdentro do método de renderização de componentes.

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


1
Às vezes, isso é muito mais útil. :)
Ferit

6

this.data presumivelmente contém todos os dados, então você precisaria fazer algo assim:

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

Ou você pode usar mapas funções de seta e se estiver usando ES6:

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

2
Isso não funcionará na versão React atual, você não pode retornar um array.
Aftab Naveed

@AftabNaveed obrigado, eu atualizei, o render deve retornar um elemento, mas é válido ter um array de elementos dentro dele
Dominic

Como @AftabNaveed diz, se a versão de reação <16, você precisará usar acima, caso contrário, você pode apenas return stations;( codepen.io/pawelgrzybek/pen/WZEKWj )
Canja de Galinha

1

Existem algumas maneiras que podem ser usadas.

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

Solução 1

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

Solução 2

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

Editar kind-antonelli-z8372

Claro que também existem outras formas disponíveis.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.