Loop inside React JSX

Loop inside React JSX



I'm trying to do something like the following in React JSX (where ObjectRow is a separate component):


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

</tbody>



I 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, I am unsure how I would achieve the above (adding a component multiple times).





It's important to note that in JSX you need the tags around your JavaScript Syntax. This may help facebook.github.io/react/docs/….
– Isaiah Grey
Dec 24 '15 at 18:25





let todos = this.props.todos.map((todo) => return <h1>todo.title</h1>)
– OverCoder
Jan 15 '17 at 19:58



let todos = this.props.todos.map((todo) => return <h1>todo.title</h1>)




45 Answers
45



Think of it like you're just calling JavaScript functions. You can't put a for loop inside a function call:


for


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

)



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


var rows = ;
for (var i = 0; i < numrows; i++)
rows.push(ObjectRow());

return tbody(rows);



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





It's possible the compiler has changed, as this example doesn't seem to compile in the jsx compiler, but using map as in FakeRainBrigand's answer below does seem to compile correctly.
– rav
Jul 2 '14 at 11:44






I can promise that the last example still compiles correctly on the latest JSX compiler.
– Sophie Alpert
Jul 2 '14 at 16:56





This works well. FakeRainBrigand's answer works for simple array iteration, but this answer is a must for scenarios where you can't use map (e.g. you don't have a collection stored in a variable).
– Kelvin
Aug 8 '14 at 16:25



map





React needs to update dom efficiently, in this case, the parent should assign a key to each childern. REF: facebook.github.io/react/docs/…
– qsun
Jan 2 '16 at 22:36


key





This is example will work, but it misses some important bits like key property and also a code style that is not really used in React code-bases. Please consider this answer stackoverflow.com/questions/22876978/loop-inside-react-jsx/… as a correct one.
– okonetchnikov
Oct 31 '16 at 14:57


key



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>





Map makes more sense if the iteratee is an array; A for loop is appropriate if it is a number.
– Code Whisperer
Apr 26 '15 at 18:40





<tbody>objects.map((o, i) => <ObjectRow obj=o key=i/></tbody> using Reactify's ES6 support or Babel.
– Steve Taylor
Jul 27 '15 at 10:24


<tbody>objects.map((o, i) => <ObjectRow obj=o key=i/></tbody>





+1. I'm even using this with a ul (unordered list). <ul> objects.map((object:string,i:number)=> return <li>object</li> ) </ul> using TypeScript
– Roberto C Navarro
Sep 28 '15 at 20:10



<ul> objects.map((object:string,i:number)=> return <li>object</li> ) </ul>





this is great, but you cannot map over an object.. for that I would use for..in
– Damon
Jan 15 '16 at 19:09


for..in





Bear in mind that the order of keys is arbitrary when using Object.keys. I find that storing the order of keys separately works well, and also the order on the object literal if necessary. That allows me to write code like this.props.order.map((k)=><ObjectRow key=k ...this.props.items[k] />)
– tgrrr
Mar 15 '16 at 8:04


this.props.order.map((k)=><ObjectRow key=k ...this.props.items[k] />)



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:


map()



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.


Array.from


v5.8.23


Array



Vanilla ES5


Array.apply


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



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>



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


Array



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


Array.prototype.fill


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


fill()


fill()



key


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.


key





What about yield? Pushing elements into an intermediate array is kind of ugly when we have generators. Do they work?
– mpen
Sep 12 '15 at 5:58


yield





@Mark I don't know that generators are really applicable here. The key thing for this in the context of JSX is an expression that returns an array. So if you were going to use a generator somehow you'd probably spread it anyway, and it'd probably be more verbose than the ES2015-based solutions here.
– JMM
Sep 12 '15 at 11:56





How is this more verbose? And why wouldn't JSX accept any iterable, not just arrays?
– mpen
Sep 12 '15 at 17:34





@Mark That is indeed less verbose than the (ES5) IIFE example I used, but it's considerably more verbose than the [...Array(x)].map(() => <El />)) version, which I think is the most elegant, and why I featured it. Re: the second question, that's a great point. 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 I couldn't say without looking at the source. Do you know? It's an intriguing question.
– JMM
Sep 12 '15 at 19:49



[...Array(x)].map(() => <El />))





@corysimmons Cool, thanks for the info on fill(). I remember now that the reason I hesitated on that is a question about how optionality of parameters is indicated in the ES spec (have to look into that sometime). The comma is just a way to elide an array element -- in this case the first one. You can do that if you want the indexes to be from 1..length of the array you're spreading rather than 0..length-1 of the spread array (because elided elements just contribute to the length of the array and don't have a corresponding property).
– JMM
Oct 25 '16 at 15:29


fill()



Simply using map Array method with ES6 syntax:


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



Don't forget the key property.


key



Using Array map function is very common way to loop through an Array of elements and create components according them in React, this is a great way to do a loop which is pretty efficient and tidy way to do your loops in JSX, It's not the only way to do it, but the preferred way.


Also, don't forget having a unique Key for each iteration as required. Map function creates a unique index from 0 but it's not recommended using the index but if your value is unique or if there is a unique key, you can use them:


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



Also few line from MDN if you not familiar with map function on Array:



map calls a provided callback function once for each element in an
array, in order, and constructs a new array from the results. callback
is invoked only for indexes of the array which have assigned values,
including undefined. It is not called for missing elements of the
array (that is, indexes that have never been set, which have been
deleted or which have never been assigned a value).



callback is invoked with three arguments: the value of the element,
the index of the element, and the Array object being traversed.



If a thisArg parameter is provided to map, it will be used as
callback's this value. Otherwise, the value undefined will be used as
its this value. This value ultimately observable by the callback is
determined according to the usual rules for determining the this seen
by a function.



map does not mutate the array on which it is called (although
callback, if invoked, may do so).





Array#map is not async!
– philraj
Aug 17 '17 at 1:51


Array#map



If you're already using lodash, the _.times function is handy.


_.times


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






Array.prototype.map could be a great option here if you aren't including a library such as lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….
– Isaiah Grey
Dec 24 '15 at 18:28





@IsaiahGrey Only if you've already got an array. Sometimes you just want to repeat stuff a few times.
– mpen
Dec 24 '15 at 18:29





sure of course! Lot's of different approaches for sure depending on the actual data. I found that more often than not in our development process we have been able to fit map in because of how are data if modeled. Great example using lodash! Btw, are you using the property initializer syntax to bind your methods to your components?
– Isaiah Grey
Dec 24 '15 at 18:33





@IsaiahGrey I think they're just called ES6 method definitions
– mpen
Feb 22 '16 at 16:39



You can also extract outside the return block:


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


return (<tbody>rows</tbody>);



I know this is an old thread, but you might want to checkout http://wix.github.io/react-templates/, which does let you use jsx-style templates in react, with a few directives (such as rt-repeat).



Your example, if you used react-templates, would be:


<tbody>
<ObjectRow rt-repeat="obj in objects"/>
</tbody>



if numrows is a array, and it's very simple.


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



Array data type in React is very better, array can back new array, and support filter, reduce etc.





This is not a decent answer as it does not make use of a key.
– kojow7
Sep 20 '17 at 21:55




There are several answers pointing to using the map statement. Here is a complete example using an iterator within the FeatureList component to list Feature components based on a JSON data structure called features.


map


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



You can view the complete FeatureList code on GitHub. The features fixture is listed here.



let us say we have an array of items in your state:


[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>





I think you may need to get rid of the after the map(item), that seemed to work them for me.
– Ian
Dec 10 '16 at 17:22



Simply use .map() to loop through your collection and return <ObjectRow> items with props from each iteration.


.map()


<ObjectRow>



Assuming objects is an array somewhere...


objects


<tbody>
objects.map((obj, index) => <ObjectRow obj= obj key= index /> )
</tbody>



If you opt to convert this inside return( ) of render method, easiest option would be using map( ) method. Map your array into JSX syntax using map() function, as shown below (ES6 syntax is used).



Inside parent component:



<tbody>
objectArray.map((object, index) => <ObjectRow key=index object=object>)
</tbody>


<tbody>
objectArray.map((object, index) => <ObjectRow key=index object=object>)
</tbody>



Please note the key attribute added to your child component. If you didn't provide key attribute, you can see the following warning on your console.


key



Warning: Each child in an array or iterator should have
a unique "key" prop.



Now at the ObjectRow component you can access the object from it's properties.



Inside ObjectRow component



const object = this.props


const object = this.props



or



const object = this.props.object


const object = this.props.object



This should fetch you the object you passed from parent component to the variable object in ObjectRow component. Now you can spit out the values in that object according to your purpose.


object



References :



map() method in Javascript



ECMA Script 6 or ES6



An ES2015 / Babel possibility is using a generator function to create an array of JSX:


function* jsxLoop(times, callback)

for(var i = 0; i < times; ++i)
yield callback(i);


...

<tbody>
[...jsxLoop(numrows, i =>
<ObjectRow key=i/>
)]
</tbody>



I use this:


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



PD: never forget the key or you will have a lot of warnings !





Or use the array index if your items don't have an .Id property, like items.map( (item, index) => <Foo key=index>item</Foo>
– kontur
Mar 30 '17 at 9:26



.Id


items.map( (item, index) => <Foo key=index>item</Foo>



...Or you can also prepare an array of objects and map it to a function to have the desired output. I prefer this, because it helps me to maintain the good practice of coding with no logic inside the return of 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>
)



you can of course solve with a .map as suggested by the other answer. If you already use babel, you could think about using jsx-control-statements
They require a little of setting, but I think it's worth in terms of readability (especially for non-react developer).
If you use a linter, there's also eslint-plugin-jsx-control-statements



Your JSX code will compile into pure JavaScript code, any tags will be replaced by ReactElement objects. In JavaScript, you cannot call a function multiple times to collect their returned variables.


ReactElement



It is illegal, the only way is to use an array to store the function returned variables.



Or you can use Array.prototype.map which is available since JavaScript ES5 to handle this situation.


Array.prototype.map



Maybe we can write other compiler to recreate a new JSX syntax to implement a repeat function just like Angular's ng-repeat.


ng-repeat



This can be done in multple ways.


return



Loop inside return


return



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



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



ES2015 Array.from with the map function + key



If you have nothing to .map() you can use Array.from() with the mapFn to repeat elements:


.map()


Array.from()


mapFn


<tbody>
Array.from( length: 5 , (v, k) => <ObjectRow key=k />)
</tbody>



I tend to favor an approach where programming logic happens outside the return value of render. This helps keep what is actually rendered easy to grok.


render



So I'd probably do something like:


import _ from 'lodash';

...

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

return <tbody>objectRows</tbody>;



Admittedly this is such a small amount of code that inlining it might work fine.





Big fan of lodash map for iterating through objects. I would be inclined to import map from 'lodash' so you are not importing all lodash functions if you don't need them though.
– Stretch0
Mar 8 at 11:11


import map from 'lodash'





These days we don't even need lodash map--just map over the array directly.
– Adam Donahue
Mar 9 at 22:19





Yeah but you can't loop through an object with es6 map(), only arrays. That's what I was saying lodash is good for looping over an object.
– Stretch0
Mar 12 at 9:26


map()





I thought you meant objects as in a list of things, my mistake.
– Adam Donahue
Mar 13 at 13:24


objects



I use it like


<tbody>
numrows ? (
numrows.map(obj => return <ObjectRow /> )
) : null
</tbody>



There are multiple ways to go about doing this. JSX eventually gets compiled to JavaScript, so as long as you're writing valid JavaScript, you'll be good.



My answer aims to consolidate all the wonderful ways already presented here:



If you do not have an array of object, simply the number of rows:



within the return block, creating an Array and using Array.prototype.map:


return


Array


Array.prototype.map


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



outside the return block, simply use a normal JavaScript for-loop:


return


render()
let rows = ;
for (let i = 0; i < numrows; i++)
rows.push(<ObjectRow key=i/>);

return (
<tbody>rows</tbody>
);



immediately invoked function expression:


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

return rows;

</tbody>
);



If you have an array of objects



within the return block, .map() each object to a <ObjectRow> component:


return


.map()


<ObjectRow>


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



outside the return block, simply use a normal JavaScript for-loop:


return


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

return (
<tbody>rows</tbody>
);



immediately invoked function expression:


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

return rows;

</tbody>
);



Since you are writing Javascript syntax inside JSX code, you need to wrap your Javascript in curly braces.


row = () =>
var rows = ;
for (let i = 0; i<numrows; i++)
rows.push(<ObjectRow/>);

return rows;

<tbody>
this.row()
</tbody>



To loop for a number of times and return, you can achieve it with the help of from and map:


from


map


<tbody>

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

</tbody>



where i = number of times


i = number of times



Here's a simple solution to it.


var Object_rows=;
for (var i=0; i < numrows; i++)
Object_rows.push(<ObjectRow/>)

<tbody>
Object_rows
</tbody>



No mapping and complex code required.You just need to push the rows to array and return the values to render it.



You can do something like:


let foo = [1,undefined,3]
foo.map(e => !!e ? <Object /> : null )



Here is a sample from React doc:
https://facebook.github.io/react/docs/jsx-in-depth.html#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>
);



as your case, I suggest writing like this:


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



Please notice the Key is very important, because React use Key to differ data in array.



Great question.



What I do when I want to add a certain number of components is use a helper function.



Define a function that returns JSX:


const myExample = () =>
let myArray =
for(let i = 0; i<5;i++)
myArray.push(<MyComponent/>)

return myArray


//... in JSX

<tbody>
myExample()
</tbody>



You can also use a self-invoking function:


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

return row

)()
</tbody>





Using anonymous functions inside render is not considered a good practice in react, as these functions need to be re-created or discarded on each re-render.
– Vlatko Vlahek
Sep 29 '17 at 7:25





it will not affect performance in this example.
– degr
Oct 12 '17 at 13:44




Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



Would you like to answer one of these unanswered questions instead?

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

ャフサォクコ ケウ,コ,ワ メ,ロスョノ゙,クネ,フムカヤヲニ,エコ゚ツ ウイオン゙ケワサネォキモュキォウイノンコチ゚メヌナイゥフュ,カヒウネェ ネ,ホノケ,ムュキ ッボーミュハ,チ ツス ィ メウイマヤ,゙ウチ ヅ ロ,ォジヌェ ャヌット ェ,マャ,チナエヒネソキツテ トホヲヲミーァ

How do I collapse sections of code in Visual Studio Code for Windows?