javascriptjson

Mapping through these JSON elements


Struggling with this a little bit. I have a json file that looks like following with a number of items nested in an array.

"projects": [
    {
      "projectOne": {
        "id": "id1",
        "company": "company1",
        "heading": "heading",
        "link": "link",
        "heroImage": "imageLink"
      }
    },
        {
      "projectTwo": {
        "id": "id2",
        "company": "company2",
        "heading": "heading",
        "link": "link",
        "heroImage": "imageLink"
      }
    },

I'd like to map through each of the projects so I'm using this to access the projects in my JSON. I'd like to name each one so I can access it easier later in other places.

  const projects = props.cmsData.projects

  {projects.map(project => {
     return <WorkGridItem {...project} key={project.id} />
  })}

And then in my component I'm using this

export default function WorkGridItem(props) {
  return (
    <div className={`${styles.item} fadeIn`} id={props.id}>
      <div>
        {props.heroImage && (
          <div className={`${styles.imageContainer}`}>
            <Image
              src={props.heroImage}
              fill
              alt={props.id} />
          </div>
        )
        }
      </div>

However, it's not accessing the elements. I kind of know why, because it's actually just mapping through the titles "projectOne" "projectTwo" etc, but I don't know how to get it to go into the element to get the id and heroImage.


Solution

  • First, you need to transform the data structure to make it easier to work with like-

    const transformProjects = (projectsData) => {
      return projectsData.map(project => {
        const projectKey = Object.keys(project)[0];
        return project[projectKey];
      });
    };
    

    Then, In your main component:

    const ProjectGrid = (props) => {
      const projects = transformProjects(props.cmsData.projects);
    
      return (
        <div>
          {projects.map(project => (
            <WorkGridItem {...project} key={project.id} />
          ))}
        </div>
      );
    };
    

    Finally, in your WorkGridItem component remains the same

    const WorkGridItem = (props) => {
      return (
        <div className={`${styles.item} fadeIn`} id={props.id}>
          <div>
            {props.heroImage && (
              <div className={`${styles.imageContainer}`}>
                <Image
                  src={props.heroImage}
                  fill
                  alt={props.id} 
                />
              </div>
            )}
          </div>
        </div>
      );
    };
    

    The key change here is the transformProjects function, which:

    1. Takes your original projects array
    2. Maps through each project object
    3. Gets the key ("projectOne", "projectTwo", etc.) using Object.keys(project)[0] and finally returns the actual project data inside that key