Loop inside React JSX Loop inside React JSX reactjs reactjs

Loop inside React JSX


Think of it like you're just calling JavaScript functions. You can't use a for loop where the arguments to a function call would go:

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

See how the function tbody is being passed a for loop as an argument – leading to a syntax error.

But you can make an array, and then pass that in as an argument:

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

You can basically use the same structure when working with JSX:

var rows = [];for (var i = 0; i < numrows; i++) {    // note: we are adding 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>;

Incidentally, my JavaScript example is almost exactly what that example of JSX transforms into. Play around with Babel REPL to get a feel for how JSX works.


I am not sure if this will work for your situation, but often map is a good answer.

If this was your code with the for loop:

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

You could write it like this with map:

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

ES6 syntax:

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


If you don't already have an array to map() like @FakeRainBrigand's answer, and want to inline this so the source layout corresponds to the output closer than @SophieAlpert's answer:

With ES2015 (ES6) syntax (spread and arrow functions)

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

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

Re: transpiling with Babel, its caveats page says that Array.from is required for spread, but at present (v5.8.23) that does not seem to be the case when spreading an actual Array. I have a documentation issue open to clarify that. But use at your own risk or polyfill.

Vanilla ES5

Array.apply

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

Inline IIFE

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>

Combination of techniques from other answers

Keep the source layout corresponding to the output, but make the inlined part more compact:

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

With ES2015 syntax & Array methods

With Array.prototype.fill you could do this as an alternative to using spread as illustrated above:

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

(I think you could actually omit any argument to fill(), but I'm not 100% on that.) Thanks to @FakeRainBrigand for correcting my mistake in an earlier version of the fill() solution (see revisions).

key

In all cases the key attr alleviates a warning with the development build, but isn't accessible in the child. You can pass an extra attr if you want the index available in the child. See Lists and Keys for discussion.