Representar componentes de React a partir de una matriz de objetos

98

Tengo algunos datos llamados estaciones, que es una matriz que contiene objetos.

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

Me gustaría representar un componente de interfaz de usuario para cada posición de la matriz. Hasta ahora puedo escribir

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

Y luego render

render(){
 return (
   {stationsArr}
 )
}

El problema es que estoy imprimiendo todos los datos. En su lugar, quiero mostrar una clave como, {this.data.call}pero eso no imprime nada.

¿Cómo puedo recorrer estos datos y devolver un nuevo elemento de interfaz de usuario para cada posición de la matriz?

thatgibbyguy
fuente
Podría estar equivocado, pero creo que debe usar en stationsArrlugar de stationsdentro de la renderfunción.
Tahir Ahmed

Respuestas:

151

Puede asignar la lista de estaciones a ReactElements.

Con React> = 16, es posible devolver múltiples elementos del mismo componente sin necesidad de un contenedor de elementos html adicional. Desde 16.2, hay una nueva sintaxis <> para crear fragmentos. Si esto no funciona o no es compatible con su IDE, puede usarlo <React.Fragment>en su lugar. Entre 16.0 y 16.2, puede usar un polyfill muy simple para fragmentos.

Prueba lo siguiente

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

¡No olvide el keyatributo!

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

Sebastien Lorber
fuente
@thatgibbyguy: ¡Oh, sí! esa podría ser la respuesta correcta. Es necesario que haya una envoltura alrededor de los componentes secundarios. Tu renderfunción debe devolver un solo elemento.
Tahir Ahmed
¿Cuál sería la razón para sugerir un atributo clave para cada elemento de la estación? Lo que pregunto es, ¿qué cambiaría eso si no es necesario ahora?
thatgibbyguy
4
@thatgibbyguy en este caso no trae mucha ventaja. En ejemplos más avanzados, permite tener mejores rendimientos de renderizado, ya que React puede saber fácilmente si un nodo existente se ha movido a otro lugar en la matriz de la estación, evitando así destruir y recrear un nodo dom existente (y también mantener el nodo dom montado) . Está en el documento de reacción: facebook.github.io/react/docs/reconciliation.html#keys
Sebastien Lorber
Un poco fuera de tema, pero no estoy seguro de cómo construir una consulta para preguntar esto. Al usar la sintaxis de ES6 en su ejemplo anterior, ¿cómo haría uno para pasar el índice del mapa? IOW, ¿cómo puedo saber si estoy en el último nodo de la matriz? Traté de envolver en parens y no pareció ir bien.
Lane Goolsby
@ElHombre stations.map((station,index) => { })funciona bien para mí
Sebastien Lorber
46

Tengo una respuesta que podría resultar un poco menos confusa para principiantes como yo. Puede usarlo mapdentro del método de representación de componentes.

render () {
   return (
       <div>
           {stations.map(station => <div key={station}> {station} </div>)} 
       </div>
   );
}
Thomas Valadez
fuente
11
Esto necesita un keyapoyo reactjs.org/docs/lists-and-keys.html#keys
David Barratt
1
A veces esto es mucho más útil. :)
ferit
6

this.data presumiblemente contiene todos los datos, por lo que necesitaría hacer algo como esto:

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

O puede usar maplas funciones de flecha y si está usando ES6:

const stations = this.data.stations.map(station =>
    <div key={station.call} className="station">
      Call: {station.call}, Freq: {station.frequency}
    </div>
);
Dominic
fuente
2
Esto no funcionará en la versión actual de React, no puede devolver una matriz.
Aftab Naveed
@AftabNaveed gracias lo he actualizado, el render debería devolver un elemento pero es válido tener una matriz de elementos dentro de eso
Dominic
Como dice @AftabNaveed, si la versión de reacción <16, deberá usar la anterior, de lo contrario, puede simplemente return stations;( codepen.io/pawelgrzybek/pen/WZEKWj )
Chicken Soup
1

Hay un par de formas que se pueden utilizar.

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

Solución 1

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

Solucion 2

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

Editar kind-antonelli-z8372

Por supuesto, también hay otras formas disponibles.

Mes.
fuente