Search code examples
reactjsjsxgatsby

Show/Hide Section in dropdown menu for Gatsby Site


I am working on a Gatsby project.

I want to keep a folder of employees, each employee has it's own folder like src/staff/hanna-rosenfeld/... containing a index.mdx and a image file.

I want to source the staff's names and images to use in a component.

The goal is to build this: enter image description here

my gatsby-config:


    module.exports = {
      siteMetadata: {
          title: "Musikschule Weimar",
      },
        plugins: [
        "gatsby-plugin-image",
        "gatsby-plugin-sharp",
        {
            resolve: `gatsby-source-filesystem`,
            options: {
            name: `pages`,
            path: `${__dirname}/src/pages/`,
            },
        },
        {
            resolve: "gatsby-source-filesystem",
            options: {
            name: `staff`,
            path: `${__dirname}/src/staff`,
            }
        },
        "gatsby-plugin-mdx",
        "gatsby-transformer-sharp",
        "gatsby-transformer-remark",
        `gatsby-remark-images`,
        ],
    };

I already got the component that is doing the dropdown working:

import * as React from 'react'
import { useState, useEffect } from "react"
import { useStaticQuery, graphql } from 'gatsby'
import { BiChevronDown } from "react-icons/bi";

import StaffList from "./StaffList"



const rows = [
    {
    id: 1,
    title: "Verantwortliche",
    },
    {
    id: 2,  
    title: "Lehrende der Zupfinstrumente",
    instrument: "zupfinstrumente"
    },
    {
    id: 3,  
    title: "Lehrende der Blechblasinstrumente",
    },
    {
    id: 4,  
    title: "Lehrende des Tasteninstruments",
    },
    {
    id: 5,  
    title: "Lehrende des Gesangs",
    },
    {
    id: 6,  
    title: "Lehrende des Schlagzeugs",
    },
    {
    id: 7,  
    title: "Lehrende des Akkordeons",
    },
    {
    id: 8,  
    title: "Lehrende der Musiktheorie",
    },
    {
    id: 9,  
    title: "Lehrende der Früherziehung",
    }
]


class DropDownRows extends React.Component {
    constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
    this.setState(prevState => ({
        isToggleOn: !prevState.isToggleOn
    }));
    }
    render() {
    return (
        <div className="dropdown-rows">
        {rows.map(row => (
        <div key={row.id}>
            <div className="row">
            <div className="col">{row.title}</div>
            <div className="col">
                <BiChevronDown
                onClick={this.handleClick}
                style={{float: "right"}}/>
            </div>
            <div>
            </div>
            </div>
            {this.state.isToggleOn ? <StaffList /> : ''}
        </div>
        ))}
    </div>
    )
    }
}

export default DropDownRows

src/staff/hanna-rosenfeld/index.mdx

---
title: Hanna Rosenfeld
featuredImage: ./Foto_05.jpg
---

Hi, mein Name ist Hanna und ich bin ein full time web developerin.

my StaffList component:

import * as React from 'react'
import { StaticQuery, graphql } from 'gatsby'
import { GatsbyImage, getImage } from "gatsby-plugin-image"

    
function StaffList({ data }) {
    return(
    <StaticQuery
    query={graphql`
        query staffQuery {
        allMdx {
            edges {
            node {
                id
                body
                frontmatter {
                title
                featuredImage {
                    childImageSharp {
                    fluid {
                        ...GatsbyImageSharpFluid
                    }
                    }
                }
                }
            }
            }
        }
        }       
        `}

        render={data => (
        <div>
        <h1>{data.allMdx.edges.map(edge => <h1 key={edge.node.id} data={edge.node}>{edge.node.frontmatter.title}</h1>)}</h1>
        <GatsbyImage alt='some alt text' image={getImage(data.allMdx.edges.map(edge => edge.node.frontmatter.featuredImage))} />
        </div>
    )}
    />
    )
}



export default StaffList

Querying for featuredImage works in graphiql, but i cannot get the image to show. Console output:

"Warning: Failed prop type: The prop image is marked as required in GatsbyImage, but its value is undefined."

The current state of the component on the site is this: enter image description here

Getting the names to show up only in their category is another problem, for now I just want the images to show.

Thank you for any insight on a possible solution in advance.


Solution

  • There are a few things to comment on here:

    The render structure is weird. You should do a loop through your data, as you are doing to display the h1 but at the same time, you can take advantage of the loop to display the image of each employee.

    In addition, you are using a Gatsby Image v2 GraphQL query structure (gatsby-image) while the render component (GatsbyImage) is from v3 (gatsby-plugin-image). I'd recommend reading the migration guide.

    To summarize, when you query for fluid or fixed images as you do while using the ...GatsbyImageSharpFluid fragment you are querying a v2 structure and the render component should be Img(from gatsby-image), that is accepting a fixed or a fluid image. However, when you use a GatsbyImage component, the passed prop should be a image (no matter if it's fixed or fluid). So, you have conflicting plugins and structures. You should get rid of one of them and use the corresponding structure. To recap:

    • fixed or fluid GraphQL query: v2 structure, the render component is Img
    • GatsbyImage component: v3 structure. I will base my answer on that assuming that you will migrate to v3 (v2 is deprecated).

    The issue rises up because as I said,GatsbyImage is expecting an image prop while you are passing a loop at and a wrong query data at:

    <GatsbyImage alt='some alt text' image={getImage(data.allMdx.edges.map(edge => edge.node.frontmatter.featuredImage))} />
    

    Use something simpler as:

       <div>
            {data.allMdx.edges.map(edge => (
             <article>
              <h1 key={edge.node.id}>{edge.node.frontmatter.title}</h1>
              <GatsbyImage alt='some alt text' image={getImage(edge.node.frontmatter.featuredImage)} />
             </article> 
            ))}
            </div>
    

    When you end the migration, the full snippet should look like:

    import * as React from 'react'
    import { StaticQuery, graphql } from 'gatsby'
    import { GatsbyImage, getImage } from "gatsby-plugin-image"
    
        
    function StaffList({ data }) {
        return(
        <StaticQuery
        query={graphql`
            query staffQuery {
            allMdx {
                edges {
                node {
                    id
                    body
                    frontmatter {
                    title
                    featuredImage {
                     childImageSharp {
                       gatsbyImageData(
                         width: 200
                         placeholder: BLURRED
                         formats: [AUTO, WEBP, AVIF]
                       )
                     }
                    }
                    }
                }
                }
            }
            }       
            `}
    
            render={data => (
             <div>
            {data.allMdx.edges.map(edge => (
             <article>
              <h1 key={edge.node.id}>{edge.node.frontmatter.title}</h1>
              <GatsbyImage alt='some alt text' image={getImage(edge.node.frontmatter.featuredImage)} />
             </article> 
            ))}
            </div>
        )}
        />
        )
    }
    
    
    
    export default StaffList
    

    Check the opening/closing brackets and to clean the cache while changing the data sources by running gatsby clean.