171

I am using React/JSX and Lodash in my app in order to accomplish what I want.

I need to repeat an element a certain amount of times depending on a condition. How should I do that?

Here is the element:

<span className="busterCards">♦</span>;

And I am assigning it like this:

let card;
if (data.hand === '8 or more cards') {
  card = <span className='busterCards'>♦</span>;
}

So in this case, I need to repeat the element 8 times. What should be the process using Lodash?

Jeffmagma
  • 452
  • 2
  • 8
  • 20
StillDead
  • 1,879
  • 2
  • 10
  • 12

12 Answers12

496

The shortest way to do this without any external libraries:

const n = 8; // Or something else

[...Array(n)].map((e, i) => <span className="busterCards" key={i}>♦</span>)
Waiski
  • 9,214
  • 3
  • 21
  • 30
  • 15
    Awesome answer for non-lodash users! Worth pointing out that it does require ES6 features (though I think it's implied by using `let` in the question anyway). – pseudoramble Oct 14 '16 at 02:09
  • 7
    For those using Typescript 2+, this will compile into `Array(3).slice().map(...)` which doesn't achieve the same result. See @Jian's answer below as a replacement. – Pierre vDEV Jan 29 '18 at 14:23
  • 1
    Nice, see my [answer](https://stackoverflow.com/a/51359938/104380) which elaborates more – vsync Jul 16 '18 at 11:15
  • Typescript recently added a tsconfig flag `"downlevelIteration": true` which _will_ compile this code correctly to ES5. – kingdaro Aug 05 '18 at 16:36
  • 5
    Why can't this just be `Array(n).map((e, i) => )` – Kevin Wang Jun 04 '19 at 21:30
  • 13
    @KevinWang because your suggestion will create an **empty** array with a length of 8, rather than an array consisting of 8 undefined items. Iteration won't work on the former. Chuck it in the console to see the difference. – Darbio Jun 13 '19 at 23:04
  • This is working as expected in Typescript version 4 – somethingRandom May 30 '22 at 11:53
  • This conflicts with `eslint-plugin-react` rule called [`react/no-array-index-key`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md), but I can't think of a better way... Guess I'll just have to disable that rule. – Garrett Oct 09 '22 at 21:12
  • 1
    @Garrett that rule's documentation explicitly says to not use the rule "If there is nothing unique about the items" - which is literally the case here. Therefore you shouldn't feel bad disabling the linter rule here. – Waiski Feb 06 '23 at 15:00
65

solution without lodash or ES6 spread syntax:

Array.apply(null, { length: 10 }).map((e, i) => (
  <span className="busterCards" key={i}>
    ♦
  </span>
));
Weihang Jian
  • 7,826
  • 4
  • 44
  • 55
  • This seems more clean, but with more iterations than around 126000 I'm getting "Maximum call stack size exceeded" (at least in Chrome web desktop) – jave.web Feb 26 '22 at 22:56
  • I came across a coworker using this code, and using Array.apply to loop a specific number of times was not intuitive to me at first glance. I'd personally consider other more intuitive solutions first if future devs will read your code. – Logan Cundiff Apr 11 '22 at 17:02
  • I am sorry to hear about that. The solution aims to use as less dependencies as possible. I would suggest your coworker improving the readability by making it a reusable function with sensible name like `times`. – Weihang Jian Apr 12 '22 at 04:22
44

Here you go:

let card = [];
_.times(8, () => {
  card.push(<span className="busterCards">♦</span>);
});

You may want to add key to each span element so React won't complain about missing the key attribute:

let card = [];
_.times(8, (i) => {
  card.push(<span className="busterCards" key={i}>♦</span>);
});

For more info about .times, refer here: https://lodash.com/docs#times

Long Nguyen
  • 11,075
  • 2
  • 18
  • 25
32

Implementing this without Lodash

<section>
      {Array.from({ length: 10 }, (_, i) => <span key={i}>Your text</span>)}
 </section>

How does this work?

Array.from() is used in two contexts:

  1. Creating an array from an array-like data structure. For example, we can convert a map into an array using Array.from()

    const map = new Map([ [1, 2], [3, 4], [4, 5] ])

    console.log(Array.from(map)) //gives an array - [[1, 2], [3, 4], [4, 5]]

  2. Creating an array and filling out the values (This can be handy when we need to create an array containing more elements)

Array.from() accepts an object and a callback function.

Array.from({ length: 7 }, (() => 10)) // gives [10,10,10,10,10,10,10]

We can take advantage of the index (second parameter) inside the callback function to provide unique array elements

Array.from({ length: 4 }, ((_, i) => i + 1)) // [1,2,3,4]

Sandeep Amarnath
  • 5,463
  • 3
  • 33
  • 43
  • 3
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Al Foиce ѫ Jun 18 '21 at 08:42
14

I'm using this and works for me.

[...Array(10)].map((elementInArray, index) => ( 
    <div key={index}>
      Text in Loop
    </div>
))
7

Using _.times: https://jsfiddle.net/v1baqwxv/

var Cards = React.createClass({
    render() {
        return <div>cards {
          _.times( this.props.count, () => <span>♦</span> )
        }</div>;
    }
});
pawel
  • 35,827
  • 7
  • 56
  • 53
6

You could do it like this (without lodash):

var numberOfCards = 8; // or more.

if (data.hand >= numberOfCards) {
    var cards = [];

    for (var i = 0; i < numberOfCards; i++) {
        cards[i] = (<span className="busterCards">♦</span>);
    }
}
Allan
  • 273
  • 1
  • 8
6

Straight forward options ways to do that without any external libraries (2021):

// straight forward but without key index. Not so good for react but work fine with worning 
Array(X).fill(<span className="busterCards">♦</span>)
// with index
Array(X).fill().map((v,i)=> <span className="busterCards">♦</span>)
Array.from( Array(X), (v,i) => <span key={i} className="busterCards">♦</span> )
// same thing basically 
Array.from( {length:X}, (v,i) => <span key={i} className="busterCards">♦</span> )
[...Array(3)].map( (_,i)=> <span key={i} className="busterCards">♦</span> )
pery mimon
  • 7,713
  • 6
  • 52
  • 57
3

You can create an array with as many items as you need rendered and then map through the array to render the correct number of elements you need.

const totalItems = 8;

const items = new Array(totalItems).fill(null);


// .... then
return (
    {items.map((_, idx) => <span className="busterCards" key = {idx}>♦</span>)}
);
ceoehis
  • 700
  • 8
  • 7
1

So I was doing this today and came to this question and i think better approach is without creating an array and without any package. Which is recursion


const YourComp = ({ n }) => {
  if (n == 0) {
    return null;
  }
  return (
    <div className="py-8">
     do something
      <YourComp n={n - 1} />
    </div>
  );
};

cool?

Rajan Lagah
  • 2,373
  • 1
  • 24
  • 40
0

You can use Lodash range.

_.range(20).map((_n, i) => <MyComponent key={i}/>)
0

I thought, that if someone would like to use it in many places in the code, it would be a good idea to make it an npm package: https://www.npmjs.com/package/repeat-component. I think it will help someone :)