Tags

Other

Problem

Let's try to understand what problem are we solving right here. We are trying to do something like the following in React JSX (where ObjectRow is a separate component):


    for (var i=0; i < numrows; i++) {

        

}

We can realize and understand why this isn't valid JSX, since JSX maps to function calls. However, coming from "template" land and being new to JSX, We are unsure how we would achieve the above (adding a component multiple times).

Solution

We should think of it like we're just calling JavaScript functions. We can't put a for loop inside a function call:

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

        ObjectRow();
    }

)

But we can make an array, and then pass that in:

var rows = [];
for (var i = 0; i < numrows; i++) {

    rows.push(ObjectRow());
}

return tbody(rows);

We can use basically the same structure when working with 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();
}
return {rows};

Incidentally, the above JavaScript example is almost exactly what that example of JSX transforms into. Playing around with Babel REPL will help us to get a feel for how JSX works.

Alternatively, often map is a good answer. If this was our code with the for loop:


    for (var i=0; i < objects.length; i++) {
        

}

 

We could write it like this with map :



    {objects.map(function(object, i){
        return ;

})}

ES6 syntax:


    {objects.map((object, i) => )}

 

If we don't already have an array to map() like the above solution, and want to inline this so the source layout corresponds to the output closer than first ever solution:

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



  {[...Array(10)].map((x, i) =>
    

)}

Regarding 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 . We do have a documentation issue open to clarify that. But use at your own risk or polyfill.

Demo on Plnkr

Vanilla ES5

Array.apply()

  {Array.apply(0, Array(10)).map(function (x, i) {
    return ;
  })}

 

 

Inline IIFE



  {(function (rows, i, len) {
    while (++i <= len) {

      rows.push()
    }

    return rows;
  })([], 0, 10)}

Demo on Plnkr

Combination of techniques from other answers

Keeping the source layout corresponding to the output, but let's make the inlined part more compact:

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

})}

);

}

With ES2015 syntax & Array methods

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



  {Array(10).fill(1).map((el, i) =>
    


)}

(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.

That is indeed less verbose than the (ES5) IIFE example we used, but it's considerably more verbose than the [...Array(x)].map(() => )) version, which I think is the most elegant, and why I featured it. The great point is that there doesn't appear to be anything about JSX that precludes it, so it depends what React or another consumer of transformed JSX does with the children arguments, which we couldn't say without looking at the source.

Summary

When we have a worse code with loop and custom directive elements and we need to loop them on the front end, we have more than three ways of implementing it in React, React JSX, Vanilla JavaScript, ES2015 and Array methods and key is something valuable here and we need to include them in the loops to avoid further errors caused by the React transpiler.

 

Thanks to Praveen Kumar for being our guest writer this week.

 

 

Back to Blog

</Follow Us>