Home > Enterprise >  How to render custom elements for each item in an object (Map data structure) in React TS?
How to render custom elements for each item in an object (Map data structure) in React TS?

Time:03-24

I've been using this method to render multiple custom elements from an array but this is my first time doing it using a map data structure. It compiles fine but renders nothing. I've set up a codesandbox here.

import "./styles.css";
import React from "react";
import ImageGrid from "./ImageGrid";

interface OnlineImage {
  id: string;
  url: string;
}

export default function App() {
  const [onlineImages, setOnlineImages] = React.useState<Map<string, OnlineImage[]>>();
  
  React.useEffect(() => {
    let onlineImageMap = new Map<string, OnlineImage[]>();

    // fake api call
    onlineImageMap.set("randomImageSet1", [
      { id: "1", url: "https://picsum.photos/200" },
      { id: "2", url: "https://picsum.photos/200" }
    ]);
    onlineImageMap.set("randomImageSet2", [
      { id: "1", url: "https://picsum.photos/200" },
      { id: "2", url: "https://picsum.photos/200" }
    ]);

    // set state
    setOnlineImages(onlineImageMap);
  }, []);

  return (
    <div className="App">
      <div>Below should render my custom ImageGrid for each item in map...</div>
      <>
        {onlineImages?.forEach((imageSet, category) => {
          return (
            <>
              <div>Image Category: {category}</div>
              <ImageGrid images={imageSet} />
            </>
          );
        })}
      </>
    </div>
  );
}

CodePudding user response:

Hi Samuel: I think you should first convert the map to an Array and then use the Array.prototype.map method which actually returns a copy of the original array with your function applied to it.

As you probably already figured out the return statement does nothing within a forEach function (to be more exact it only stops the execution of the code but does not bring back anything into the outer context).

If you really want to use forEach you'll have to use an array or Object to catch it then use Object.entries/.map to iterate over it


const myMap = new Map(Object.entries({a: 1, b: 2}))
const myMapCaptureList = []
myMap.forEach((value, key) => {
myMapCaptureList.push([key, value])
}
// then you can use myMapCaptureList
myMapCaptureList.map(([key, value]) => <div>{key}: <span>{value}</span></div>);

But I would suggest that it is much easier to use the very helpful Array.from method that can help convert a Map into an array of key/value pair entries: [[key1, val1], [key2, val2]]. It is essentially equivalent to running Object.entries(someObject).

{Array.from(onlineImages || []).map(([category, imageSet]) => {
          return (
            <>
              <div>Image Category: {category}</div>
              <ImageGrid images={imageSet} />
            </>
          );
        })}

CodePudding user response:

You are using the .forEach method - which returns nothing, instead use .map that is identical but does return things

 {onlineImages?.map((imageSet, category) => 
        <>
          <div>Image Category: {category}</div>
          <ImageGrid images={imageSet} />
        </>
    )}
  • Related