0

How would you assemble this html using jsx/react. My problem is that i++ is always output as part of the html, although it is something I'd rather want to execute.

const rows = [];

for (let i = 0; i < items.length; i++) {
  let row;
  if (i + 1 < items.length) {
    // on all but the last item we have to items in a row
    row = (
      <div className="bpa-module-tile-row">
        {this.getItem(items[i])}
        i++;
        {this.getItem(items[i])}
        )
      </div>
    );
  } else {
    // if we have an odd number of items, then the last row has only one not two items in a rowj
    row = (
      <div className="bpa-module-tile-row">{this.getItem(items[i])}</div>
    );
  }

  rows.push(row);
}

The rows are then output later using {rows} in jsx. The problem is that the i++ result also ends up in the html. I feel like I am "thinking" or approaching it in a wrong way here.

How can I write this in idiomatic JSX?

nachtigall
  • 2,447
  • 2
  • 27
  • 35

3 Answers3

1

Array.prototype.map() will iterate through the list and produce another list applying the function you provide it.

Something similar to this is what you're looking for:

const items = [1,2,3,4,5]
const rows = items.map((_, index) => index % 2 ? [] : items.slice(index, index + 2))
  .filter(row => row.length > 0)
  .map(row =>
     (<div className="bpa-module-tile-row">
       {row.map(x => "Item " + x)}
     </div>)
  );

Try it out: JS fiddle


If you can import (or write your own) chunk method then this becomes even more simple:

const rows = chunk(items, size=2)
 .map(row =>
     (<div className="bpa-module-tile-row">
       {row.map(x => "Item " + x)}
     </div>)
  );
ᴘᴀɴᴀʏɪᴏᴛɪs
  • 7,169
  • 9
  • 50
  • 81
1

You can simple use i++ whereever you want inside the curly braces. Your row object must be like:

row = (
      <div className="bpa-module-tile-row">
        {this.getItem(items[i++])}
        {this.getItem(items[i])}
        )
      </div>
    );
  • Well, I am not a friend of these "hidden" i++ statements. Really easy to overlook. I'd prefer if the i++ would be a statement on a single line. – nachtigall May 17 '18 at 16:08
1

One solution is to increment your counter by 2 and calculate each index as appropriate:

const rows = [];

for (let i = 0; i < items.length; i += 2) {
  let row;
  if (i + 1 < items.length) {
    // on all but the last item we have to items in a row
    row = (
      <div className="bpa-module-tile-row">
        {this.getItem(items[i])}
        {this.getItem(items[i+1])}
        )
      </div>
    );
  } else {
    // if we have an odd number of items, then the last row has only one not two items in a rowj
    row = (
      <div className="bpa-module-tile-row">{this.getItem(items[i])}</div>
    );
  }

  rows.push(row);
}
Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268