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.