Loop dentro de React JSX

1279

Estoy tratando de hacer algo como lo siguiente en React JSX(donde ObjectRow es un componente separado):

<tbody>
    for (var i=0; i < numrows; i++) {
        <ObjectRow/>
    } 
</tbody>

Me doy cuenta y entiendo por qué esto no es válido JSX, ya que se JSXasigna a llamadas a funciones. Sin embargo, viniendo de la plantilla y siendo nuevo en JSX, no estoy seguro de cómo lograría lo anterior (agregando un componente varias veces).

Ben Roberts
fuente
38
Es importante tener en cuenta que en JSX necesita las etiquetas {} alrededor de su sintaxis de JavaScript. Esto puede ayudar a facebook.github.io/react/docs/… .
Isaiah Gray
30
let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
OverCoder
@OverCoder, ¿por qué pondría el retorno completo en la etiqueta {} sería => return <h1> {todo.title} </h1> ¿No es así?
Pravin Poudel
1
@pravinpoudel en realidad esa respuesta es antigua, más como let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

Respuestas:

1205

Piense en ello como si solo estuviera llamando a funciones de JavaScript. No puede usar un forbucle donde irían los argumentos de una llamada a la función:

return tbody(
    for (var i = 0; i < numrows; i++) {
        ObjectRow()
    } 
)

Vea cómo tbodyse pasa un forbucle a la función como argumento y, por supuesto, es un error de sintaxis.

Pero puede hacer una matriz y luego pasarla como argumento:

var rows = [];
for (var i = 0; i < numrows; i++) {
    rows.push(ObjectRow());
}
return tbody(rows);

Puedes usar básicamente la misma estructura cuando trabajas con JSX:

var rows = [];
for (var i = 0; i < numrows; i++) {
    // note: we add a key prop here to allow react to uniquely identify each
    // element in this array. see: https://reactjs.org/docs/lists-and-keys.html
    rows.push(<ObjectRow key={i} />);
}
return <tbody>{rows}</tbody>;

Por cierto, mi ejemplo de JavaScript es casi exactamente en lo que se transforma ese ejemplo de JSX. Juega con Babel REPL para tener una idea de cómo funciona JSX.

Sophie Alpert
fuente
3
Es posible que el compilador haya cambiado, ya que este ejemplo no parece compilarse en el compilador jsx , pero el uso de map como en la respuesta de FakeRainBrigand a continuación parece compilarse correctamente.
rav
99
Puedo prometer que el último ejemplo todavía se compila correctamente en el último compilador JSX.
Sophie Alpert
3
Esto funciona bien La respuesta de FakeRainBrigand funciona para una iteración de matriz simple, pero esta respuesta es imprescindible para escenarios en los que no puede usar map(por ejemplo, no tiene una colección almacenada en una variable).
Kelvin
52
React necesita actualizar dom de manera eficiente, en este caso, el padre debe asignar un keya cada niño. REF: facebook.github.io/react/docs/…
qsun
77
Este ejemplo funcionará, pero pierde algunos bits importantes como la keypropiedad y también un estilo de código que realmente no se usa en las bases de código React. Considere esta respuesta stackoverflow.com/questions/22876978/loop-inside-react-jsx/… como correcta.
okonetchnikov
867

No estoy seguro si esto funcionará para su situación, pero a menudo el mapa es una buena respuesta.

Si este fue su código con el bucle for:

<tbody>
    for (var i=0; i < objects.length; i++) {
        <ObjectRow obj={objects[i]} key={i}>
    } 
</tbody>

Podrías escribirlo así con el mapa :

<tbody>
    {objects.map(function(object, i){
        return <ObjectRow obj={object} key={i} />;
    })}
</tbody>

Sintaxis ES6:

<tbody>
    {objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
Bandido
fuente
43
El mapa tiene más sentido si el iterado es una matriz; Un bucle for es apropiado si es un número.
Code Whisperer
26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>usando el soporte ES6 de Reactify o Babel.
Distortum
3
+1. Incluso estoy usando esto con un ul (lista desordenada). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>usando TypeScript
Roberto C Navarro
55
esto es genial, pero no puedes mapear sobre un objeto ... para eso lo usaríafor..in
Damon
44
Tenga en cuenta que el orden de las teclas es arbitrario al usar Object.keys. Me parece que almacenar el orden de las teclas por separado funciona bien, y también el orden en el objeto literal si es necesario. Eso me permite escribir código comothis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr
444

Si aún no tiene una matriz que le map()guste la respuesta de @ FakeRainBrigand, y desea alinear esto para que el diseño de origen corresponda a la salida más cercana que la respuesta de @ SophieAlpert:

Con sintaxis ES2015 (ES6) (funciones de dispersión y flecha)

http://plnkr.co/edit/mfqFWODVy8dKQQOkIEGV?p=preview

<tbody>
  {[...Array(10)].map((x, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

Re: transpilando con Babel, su página de advertencias dice que Array.fromse requiere para la propagación, pero en la actualidad ( v5.8.23) ese no parece ser el caso cuando se difunde un real Array. Tengo un problema de documentación abierto para aclarar eso. Pero use bajo su propio riesgo o polyfill.

Vanilla ES5

Array.apply

<tbody>
  {Array.apply(0, Array(10)).map(function (x, i) {
    return <ObjectRow key={i} />;
  })}
</tbody>

IIFE en línea

http://plnkr.co/edit/4kQjdTzd4w69g8Suu2hT?p=preview

<tbody>
  {(function (rows, i, len) {
    while (++i <= len) {
      rows.push(<ObjectRow key={i} />)
    }
    return rows;
  })([], 0, 10)}
</tbody>

Combinación de técnicas de otras respuestas.

Mantenga el diseño de origen correspondiente a la salida, pero haga que la parte en línea sea más compacta:

render: function () {
  var rows = [], i = 0, len = 10;
  while (++i <= len) rows.push(i);

  return (
    <tbody>
      {rows.map(function (i) {
        return <ObjectRow key={i} index={i} />;
      })}
    </tbody>
  );
}

Con sintaxis y Arraymétodos ES2015

Con Array.prototype.fillusted podría hacer esto como una alternativa al uso de propagación como se ilustra arriba:

<tbody>
  {Array(10).fill(1).map((el, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

(Creo que podría omitir cualquier argumento fill(), pero no estoy al 100% en eso). Gracias a @FakeRainBrigand por corregir mi error en una versión anterior de la fill()solución (ver revisiones).

key

En todos los casos, el keyatributo alivia una advertencia con la construcción de desarrollo, pero no es accesible en el niño. Puede pasar un atributo adicional si desea que el índice esté disponible en el elemento secundario. Ver Listas y claves para la discusión.

JMM
fuente
2
¿Qué hay de yield? Insertar elementos en una matriz intermedia es algo feo cuando tenemos generadores. ¿Funcionan?
mpen
2
@ Mark No sé si los generadores son realmente aplicables aquí. La clave para esto en el contexto de JSX es una expresión que devuelve una matriz. Entonces, si fuera a usar un generador de alguna manera, probablemente lo distribuiría de todos modos, y probablemente sería más detallado que las soluciones basadas en ES2015 aquí.
JMM
2
¿Cómo es esto más detallado? ¿Y por qué JSX no aceptaría ningún iterable, no solo matrices?
mpen
2
@ Mark De hecho, es menos detallado que el ejemplo (ES5) IIFE que utilicé, pero es considerablemente más detallado que la [...Array(x)].map(() => <El />))versión, que creo que es la más elegante, y por qué lo presenté. Re: la segunda pregunta, ese es un gran punto. No parece haber nada acerca de JSX que lo impida, por lo que depende de lo que React u otro consumidor de JSX transformado haga con los argumentos secundarios, lo que no podría decir sin mirar la fuente. ¿Tú sabes? Es una pregunta intrigante.
JMM
3
@corysimmons Genial, gracias por la información sobre fill(). Ahora recuerdo que la razón por la que dudé es una pregunta acerca de cómo se indica la opcionalidad de los parámetros en la especificación ES (tengo que analizar eso en algún momento). La coma es solo una forma de eludir un elemento de matriz, en este caso el primero. Puede hacerlo si desea que los índices sean de 1..length de la matriz que está distribuyendo en lugar de 0..length-1 de la matriz de propagación (porque los elementos elididos solo contribuyen a la longitud de la matriz y no ' t tiene una propiedad correspondiente).
JMM
85

Simplemente usando el método map Array con la sintaxis ES6:

<tbody>
  {items.map(item => <ObjectRow key={item.id} name={item.name} />)} 
</tbody>

No te olvides de la keypropiedad.

danielfeelfine
fuente
Agrego una clave aleatoria 'Math.random ()' en lugar de id, no funciona bien cuando setState dentro de niños, ¿tienes idea de por qué?
Oliver D
82

El uso de la función de mapa Array es una forma muy común de recorrer una matriz de elementos y crear componentes de acuerdo con ellos en React , esta es una excelente manera de hacer un ciclo que es bastante eficiente y ordenada para hacer sus bucles en JSX , no es la única forma de hacerlo, pero la forma preferida.

Además, no olvide tener una clave única para cada iteración según sea necesario. La función de mapa crea un índice único desde 0 pero no se recomienda usar el índice producido, pero si su valor es único o si hay una clave única, puede usarlos:

<tbody>
  {numrows.map(x=> <ObjectRow key={x.id} />)}
</tbody>

Además, algunas líneas de MDN si no está familiarizado con la función de mapa en Array:

map llama a una función de devolución de llamada proporcionada una vez para cada elemento en una matriz, en orden, y construye una nueva matriz a partir de los resultados. la devolución de llamada se invoca solo para índices de la matriz que tienen valores asignados, incluidos los indefinidos. No se llama para elementos faltantes de la matriz (es decir, índices que nunca se han establecido, que se han eliminado o que nunca se les ha asignado un valor).

la devolución de llamada se invoca con tres argumentos: el valor del elemento, el índice del elemento y el objeto Array que se atraviesa.

Si se proporciona un parámetro thisArg para asignar, se utilizará como este valor de devolución de llamada. De lo contrario, el valor indefinido se utilizará como su valor. Este valor finalmente observable por la devolución de llamada se determina de acuerdo con las reglas habituales para determinar esto visto por una función.

map no muta la matriz en la que se llama (aunque la devolución de llamada, si se invoca, puede hacerlo).

Alireza
fuente
Array#mapno es asíncrono!
philraj
52

Si ya está usando lodash, la _.timesfunción es útil.

import React, { Component } from 'react';
import Select from './Select';
import _ from 'lodash';

export default class App extends Component {
    render() {
        return (
            <div className="container">
                <ol>
                    {_.times(3, i =>
                        <li key={i}>
                            <Select onSelect={this.onSelect}>
                                <option value="1">bacon</option>
                                <option value="2">cheez</option>
                            </Select>
                        </li>
                    )}
                </ol>
            </div>
        );
    }
}
mpen
fuente
1
Array.prototype.map podría ser una gran opción aquí si no incluye una biblioteca como lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Isaiah Gray
1
@IsaiahGrey Solo si ya tienes una matriz. A veces solo quieres repetir cosas varias veces.
mpen
1
¡claro, por supuesto! Muchos enfoques diferentes con seguridad dependiendo de los datos reales. Descubrí que la mayoría de las veces en nuestro proceso de desarrollo hemos podido ajustar el mapa debido a cómo se modelan los datos. Gran ejemplo usando lodash! Por cierto, ¿está utilizando la sintaxis del inicializador de propiedades para vincular sus métodos a sus componentes?
Isaiah Gray
44
@IsaiahGrey Creo que simplemente se llaman definiciones de método
mpen
41

También puede extraer fuera del bloque de retorno:

render: function() {
    var rows = [];
    for (var i = 0; i < numrows; i++) {
        rows.push(<ObjectRow key={i}/>);
    } 

    return (<tbody>{rows}</tbody>);
}
Brandon Sibeitokgong
fuente
34

Sé que este es un hilo antiguo, pero es posible que desee consultar React Templates , que le permite usar plantillas de estilo jsx en react, con algunas directivas (como rt-repeat).

Su ejemplo, si usó react-templates, sería:

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>
Etai
fuente
¿Por qué utiliza una biblioteca adicional mientras que javascript simple ya ha proporcionado una solución con varios tipos de bucle for o método Array.prototype.map para resolver el problema? Yo mismo ya he usado ambas formas simples de JavaScript en mi proyecto actual, que funcionan bien. Tener la costumbre de usar formas simples de javascript siempre que sea posible me ayuda a mejorar mi habilidad en javascript. Solo uso bibliotecas adicionales cuando parece difícil encontrar soluciones para ciertos problemas, como el enrutamiento con React-Router.
Lex Soft
27

Hay varias formas de hacerlo. JSX finalmente se compila en JavaScript, por lo que siempre que esté escribiendo JavaScript válido, será bueno.

Mi respuesta apunta a consolidar todas las formas maravillosas que ya se presentan aquí:

Si no tiene una matriz de objetos, simplemente el número de filas:

dentro del returnbloque, creando Arrayy usando Array.prototype.map:

render() {
  return (
    <tbody>
      {Array(numrows).fill(null).map((value, index) => (
        <ObjectRow key={index}>
      ))}
    </tbody>
  );
}

fuera del returnbloque, simplemente use un JavaScript for-loop normal:

render() {
  let rows = [];
  for (let i = 0; i < numrows; i++) {
    rows.push(<ObjectRow key={i}/>);
  } 
  return (
    <tbody>{rows}</tbody>
  );
}

expresión de función invocada inmediatamente:

render() {
  return (
    <tbody>
      {() => {
        let rows = [];
        for (let i = 0; i < numrows; i++) {
          rows.push(<ObjectRow key={i}/>);
        }
        return rows;
      }}
    </tbody>
  );
}

Si tienes una variedad de objetos

dentro del returnbloque, .map()cada objeto a un <ObjectRow>componente:

render() {
  return (
    <tbody>
      {objectRows.map((row, index) => (
        <ObjectRow key={index} data={row} />
      ))}
    </tbody>
  );
}

fuera del returnbloque, simplemente use un JavaScript for-loop normal:

render() {
  let rows = [];
  for (let i = 0; i < objectRows.length; i++) {
    rows.push(<ObjectRow key={i} data={objectRows[i]} />);
  } 
  return (
    <tbody>{rows}</tbody>
  );
}

expresión de función invocada inmediatamente:

render() {
  return (
    <tbody>
      {(() => {
        const rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}
Yangshun Tay
fuente
2
Grandes respuestas: varias técnicas, todas usan solo JavaScript simple que muestra el poder de javascript, gracias a sus diversas formas de realizar tareas similares.
Lex Soft
24

if numrows es una matriz, y es muy simple.

<tbody>
   {numrows.map(item => <ObjectRow />)}
</tbody>

El tipo de datos de matriz en React es mucho mejor, la matriz puede respaldar una nueva matriz y admite filtros, reducir, etc.

lulin
fuente
Esta no es una respuesta decente, ya que no utiliza una clave.
kojow7
21

Hay varias respuestas que apuntan al uso de la mapdeclaración. Aquí hay un ejemplo completo que usa un iterador dentro del componente FeatureList para enumerar los componentes Feature basados ​​en una estructura de datos JSON llamada características .

const FeatureList = ({ features, onClickFeature, onClickLikes }) => (
  <div className="feature-list">
    {features.map(feature =>
      <Feature
        key={feature.id}
        {...feature}
        onClickFeature={() => onClickFeature(feature.id)}
        onClickLikes={() => onClickLikes(feature.id)}
      />
    )}
  </div>
); 

Puede ver el código completo de FeatureList en GitHub. El accesorio de características se enumera aquí .

Manav Sehgal
fuente
Cuando trato con datos JSON, como cuando recupero datos de la base de datos usando la API fetch, confío en usar el método Array.prototype.map. Es una forma conveniente y comprobada para ese propósito.
Lex Soft
17

Para recorrer varias veces y regresar, puede lograrlo con la ayuda de fromy map:

<tbody>
  {
    Array.from(Array(i)).map(() => <ObjectRow />)
  }
</tbody>

dónde i = number of times


Si desea asignar ID de clave únicos a los componentes renderizados, puede usarlos React.Children.toArraycomo se propone en la documentación de React

React.Children.toArray

Devuelve la estructura de datos opaca de los hijos como una matriz plana con claves asignadas a cada hijo. Útil si desea manipular colecciones de elementos secundarios en sus métodos de representación, especialmente si desea reordenar o dividir this.props.children antes de pasarlo.

Nota:

React.Children.toArray()cambia las claves para preservar la semántica de las matrices anidadas al acoplar listas de elementos secundarios. Es decir, toArray coloca los prefijos de cada clave en la matriz devuelta para que la clave de cada elemento tenga un alcance en la matriz de entrada que la contiene.

<tbody>
  {
    React.Children.toArray(
      Array.from(Array(i)).map(() => <ObjectRow />)
    )
  }
</tbody>
Jee Mok
fuente
17

Si se opta para convertir esto dentro de retorno () de rendir método, opción más fácil sería utilizar un mapa () método. Asigne su matriz a la sintaxis JSX usando la función map (), como se muestra a continuación ( se usa la sintaxis ES6 ).


Componente principal interno :

<tbody>
   { objectArray.map(object => <ObjectRow key={object.id} object={object.value}>) }
</tbody>

Tenga en cuenta el keyatributo agregado a su componente hijo. Si no proporcionó un atributo clave, puede ver la siguiente advertencia en su consola.

Advertencia: cada elemento secundario en una matriz o iterador debe tener un accesorio "clave" único.

Nota: Un error común que la gente comete es usar indexcomo clave al iterar, usar indexel elemento como clave es un antipatrón y puede leer más sobre esto aquí . En resumen, si NO es una lista estática, nunca la use indexcomo clave.


Ahora en el componente ObjectRow , puede acceder al objeto desde sus propiedades.

Componente interno de ObjectRow

const { object } = this.props

o

const object = this.props.object

Esto debería obtener el objeto que pasó del componente principal a la variable objecten el componente ObjectRow . Ahora puede escupir los valores en ese objeto de acuerdo con su propósito.


Referencias

método map () en Javascript

ECMA Script 6 o ES6

bharadhwaj
fuente
16

digamos que tenemos una variedad de artículos en su estado:

[{name: "item1", id: 1}, {name: "item2", id: 2}, {name: "item3", id: 3}]

<tbody>
    {this.state.items.map((item) => {
        <ObjectRow key={item.id} name={item.name} />
    })} 
</tbody>
Jan Franz Palngipang
fuente
Creo que es posible que deba deshacerse del {} después del mapa (elemento), que parecía funcionar para mí.
Ian
15

Una posibilidad de ES2015 / Babel es utilizar una función de generador para crear una matriz de JSX:

function* jsxLoop(times, callback)
{
    for(var i = 0; i < times; ++i)
        yield callback(i);
}

...

<tbody>
    {[...jsxLoop(numrows, i =>
        <ObjectRow key={i}/>
    )]}
</tbody>
David Q Hogan
fuente
15

... O también puede preparar una matriz de objetos y asignarla a una función para obtener la salida deseada. Prefiero esto, porque me ayuda a mantener la buena práctica de codificación sin lógica dentro del retorno del render.

render() {
const mapItem = [];
for(let i =0;i<item.length;i++) 
  mapItem.push(i);
const singleItem => (item, index) {
 // item the single item in the array 
 // the index of the item in the array
 // can implement any logic here
 return (
  <ObjectRow/>
)

}
  return(
   <tbody>{mapItem.map(singleItem)}</tbody>
  )
}
Rafi Ud Daula Refat
fuente
15

Simplemente use .map()para recorrer su colección y devolver <ObjectRow>artículos con accesorios de cada iteración.

Suponiendo que objectshay una matriz en alguna parte ...

<tbody>
  { objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
Joshua Michael Waggoner
fuente
15

ES2015 Array.from con la función de mapa + tecla

Si no tiene nada .map()que pueda usar Array.from()con la mapfunción para repetir elementos:

<tbody>
  {Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>
Hacer asíncrono
fuente
15

Yo uso esto:

gridItems = this.state.applications.map(app =>
          <ApplicationItem key={app.Id} app={app } />
);

PD: ¡nunca olvides la clave o tendrás muchas advertencias!

JC
fuente
O use el índice de matriz si sus artículos no tienen una .Idpropiedad, comoitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur
13

Tiendo a favorecer un enfoque donde la lógica de programación ocurre fuera del valor de retorno de render. Esto ayuda a mantener lo que realmente se hace fácil de asimilar.

Entonces probablemente haría algo como:

import _ from 'lodash';

...

const TableBody = ({ objects }) => {
  const objectRows = objects.map(obj => <ObjectRow object={obj} />);      

  return <tbody>{objectRows}</tbody>;
} 

Es cierto que se trata de una cantidad de código tan pequeña que incluirla podría funcionar bien.

Adam Donahue
fuente
Gran fan de lodash map para iterar a través de objetos. Sin embargo, me inclinaría para import { map } from 'lodash'que no esté importando todas las funciones lodash si no las necesita.
Estirar0
En estos días ni siquiera necesitamos un mapa lodash, solo mapeamos directamente sobre la matriz.
Adam Donahue
Sí, pero no puedes recorrer un objeto con es6 map(), solo matrices. Eso es lo que estaba diciendo que lodash es bueno para recorrer un objeto.
Stretch0
Pensé que te referías objectsa una lista de cosas, mi error.
Adam Donahue
12

por supuesto, puede resolver con un .map como lo sugiere la otra respuesta. Si ya usa babel, podría pensar en usar jsx-control-sentencias. Requieren un poco de configuración, pero creo que vale la pena en términos de legibilidad (especialmente para desarrolladores que no reaccionan). Si usa un linter, también hay eslint-plugin-jsx-control-declaraciones

Jurgo Boemo
fuente
12

Su código JSX se compilará en código JavaScript puro, cualquier etiqueta será reemplazada por ReactElement objetos. En JavaScript, no puede llamar a una función varias veces para recopilar sus variables devueltas.

Es ilegal, la única forma es usar una matriz para almacenar las variables devueltas de la función.

O puede usar el Array.prototype.mapque está disponible desde JavaScript ES5 para manejar esta situación.

Tal vez podamos escribir otro compilador para recrear una nueva sintaxis JSX para implementar una función de repetición como la de Angularng-repeat .

serpientes
fuente
12

Esto se puede hacer de múltiples maneras.

  1. Como se sugirió anteriormente, antes de returnalmacenar todos los elementos en la matriz
  2. Lazo dentro return

    Método 1

     let container =[];
        let arr = [1,2,3] //can be anything array, object 
    
        arr.forEach((val,index)=>{
          container.push(<div key={index}>
                         val
                         </div>)
            /** 
            * 1. All loop generated elements require a key 
            * 2. only one parent element can be placed in Array
            * e.g. container.push(<div key={index}>
                                        val
                                  </div>
                                  <div>
                                  this will throw error
                                  </div>  
                                )
            **/   
        });
        return (
          <div>
             <div>any things goes here</div>
             <div>{container}</div>
          </div>
        )

    Método 2

       return(
         <div>
         <div>any things goes here</div>
         <div>
            {(()=>{
              let container =[];
              let arr = [1,2,3] //can be anything array, object 
              arr.forEach((val,index)=>{
                container.push(<div key={index}>
                               val
                               </div>)
                             });
                        return container;     
            })()}
    
         </div>
      </div>
    )
abhirathore2006
fuente
Si. En mi proyecto actual, uso el método 1, es decir, el método Array.prototype, forEach () para crear un elemento de selección HTML que se completa con datos de la base de datos. Sin embargo, es más probable que los reemplace con el método Array.prototype.map (), ya que el método de mapa parece más compacto (menos código).
Lex Soft
10

Aquí hay una solución simple para ello.

var Object_rows=[];
for (var i=0; i < numrows; i++) {
    Object_rows.push(<ObjectRow/>)
} 
<tbody>
  {Object_rows}
</tbody>

No se requiere mapeo ni código complejo. Solo necesita empujar las filas a la matriz y devolver los valores para representarlo.

Javasamurai
fuente
Al crear html select element, esta técnica similar fue la que primero me vino a la mente, así que la usé, aunque utilizo el método forEach (). Pero cuando volví a leer el documento React sobre temas de Listas y claves, descubrí que usan el método map () como también se muestra en varias respuestas aquí. Esto me hace pensar que es la forma preferida. Estoy de acuerdo, ya que se ve más compacto (menos código).
Lex Soft
9

Como está escribiendo la sintaxis de Javascript dentro del código JSX, debe envolver su Javascript en llaves.

row = () => {
   var rows = [];
   for (let i = 0; i<numrows; i++) {
       rows.push(<ObjectRow/>);
   }
   return rows;
}
<tbody>
{this.row()}  
</tbody>
Rohit Jindal
fuente
9

Aquí hay una muestra de React doc: JavaScript Expressions as Children

function Item(props) {
  return <li>{props.message}</li>;
}

function TodoList() {
  const todos = ['finish doc', 'submit pr', 'nag dan to review'];
  return (
    <ul>
      {todos.map((message) => <Item key={message} message={message} />)}
    </ul>
  );
}

según su caso, sugiero escribir así:

function render() {
  return (
    <tbody>
      {numrows.map((roe, index) => <ObjectRow key={index} />)}
    </tbody>
  );
}

Tenga en cuenta que la clave es muy importante, porque React usa la clave para diferenciar los datos en la matriz.

Sinka Lee
fuente
9

Lo uso como

<tbody>
  { numrows ? (
     numrows.map(obj => { return <ObjectRow /> }) 
    ) : null
  }
</tbody>
Sampath
fuente
8

Puedes hacer algo como:

let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
Gize Carolina Bonilla Madrazo
fuente
8

Gran pregunta

Lo que hago cuando quiero agregar un cierto número de componentes es usar una función auxiliar.

Defina una función que devuelva JSX:

const myExample = () => {
    let myArray = []
    for(let i = 0; i<5;i++) {
        myArray.push(<MyComponent/>)
    }
    return myArray
}

//... in JSX

<tbody>
    {myExample()}
</tbody>
Christophe Pouliot
fuente
8

También puede usar una función de invocación automática:

return <tbody>
           {(() => {
              let row = []
              for (var i = 0; i < numrows; i++) {
                  row.push(<ObjectRow key={i} />)
              }
              return row

           })()}
        </tbody>
Fba Shad
fuente
El uso de funciones anónimas dentro del render no se considera una buena práctica para reaccionar, ya que estas funciones deben volver a crearse o descartarse en cada renderizado.
Vlatko Vlahek
@VlatkoVlahek lo está confundiendo con los accesorios de función que se recrean en cada ciclo de renderizado, lo que podría conducir a un rendimiento más bajo a gran escala. Crear una función anónima en cualquier otro lugar no afectará el rendimiento de manera significativa.
Emile Bergeron
1
@EmileBergeron Esto fue hace un tiempo jaja. Estoy de acuerdo si esto no se usa como accesorio, no hay diferencia.
Vlatko Vlahek