alsoALion
alsoALion

Reputation: 469

forEach over es6 Map in JSX

I had a javascript array that was rendering components using array.map. I switched this array to an es6 Map in order to be able to use key-value pairs to find items more easily, and switched from a .map to a forEach over the Map. Inside the forEach I call a render method that returns a React component, but it isn't being rendered. How do I render a component inside the forEach?

<div className='gallery__items'>
    {resultsByGuid.forEach((result, index) => {
        key++;
        this.renderGalleryItem(result, key);
    })} 
</div>

Here is the renderGalleryItem method:

renderGalleryItem = (item, index) => {
    const { gridItemSelected, itemThumbnailRequested } = this.props;
    return (
        <GalleryItem
            key={index}
            item={item}
            onClick={gridItemSelected}
            fetchThumbnailFunc={itemThumbnailRequested}
        />
    );
};

I understand that forEach doesn't return anything but does that mean I can't render inside it?

Upvotes: 23

Views: 38707

Answers (4)

BrechtVds
BrechtVds

Reputation: 573

Just a slight improvement on danday74's example using array destructuring. With options the ES6 Map:

<select>
    {[...options].map(([key, value]) => (
        <option key={key} value={key}>
            {value}
        </option>
    ))}
</select>;

Upvotes: 20

Michael Zi&#246;rjen
Michael Zi&#246;rjen

Reputation: 27

If you call .entries() on your map you will get an iterator object which for every key/value pair contains an array with the structure: [key, value] as mentioned here.

So you could just do:

<div className='gallery__items'>
  {resultsByGuid.entries().map((result) => {
    return this.renderGalleryItem(result[1], result[0]);
  })}
</div>

I am still wondering, if there's a simpler solution though.

Upvotes: 0

danday74
danday74

Reputation: 56936

another option, where options is an es6 Map() ..

<select>
  {
    [...options].map((entry) => {
      let key = entry[0]
      let value = entry[1]
      return <option key={ key } value={ key }>{ value }</option>
    })
  }
</select>

Upvotes: 8

Rob M.
Rob M.

Reputation: 36511

You are correct, forEach doesn't return anything, use map instead, it will return an array of JSX components.

Map will allow you to access the key as well: resultsByGuid.map((item, key) => { })

Edit I apologize for jumping the gun and not reading that you were using a Map data structure. forEach won't render anything because you need the return value, you could implement your own Array.map like iterator:

const mapIterator = (map, cb) => {
  const agg = [];
  for(let [key, value] of map) {
    agg.push(cb(value, key));
  }
  return agg;
};

<div className='gallery__items'>
  {mapIterator(resultsByGuid, (result, index) => {
    key++;
    return this.renderGalleryItem(result, key);
  })}
</div>

Edit 2 And thanks to @zerkms for pointing out what should've been obvious to me:

<div className='gallery__items'>
  {Array.from(resultsByGuid.values()).map((result, index) => {
    key++;
    return this.renderGalleryItem(result, key);
  })}
</div>

Upvotes: 17

Related Questions