Search code examples
javascriptreactjsgatsbygatsby-image

React, gatsbyjs: Looping through object - Component doesn't get rendered


I have the following component in a Gatsbyjs project:

styleItem.js

import React from 'react'
import styled from 'styled-components'
import BackgroundImage from 'gatsby-background-image'
import {StaticQuery, graphql } from "gatsby"
import {Col } from 'react-bootstrap'

import '../styles/styles.css'

const StyleItem = (props) => {
    return (
        <StaticQuery 
            query={graphql`
                query {
                    street: file(relativePath: { eq: "2.jpg" }) {
                        childImageSharp {
                        fluid(quality: 90, maxWidth: 1920) {
                            ...GatsbyImageSharpFluid_withWebp
                            }
                        }
                    }
                    casual: file(relativePath: { eq: "3.jpg" }) {
                        childImageSharp {
                        fluid(quality: 90, maxWidth: 1920) {
                            ...GatsbyImageSharpFluid_withWebp
                            }
                        }
                    }
                    athletic: file(relativePath: { eq: "3.jpg" }) {
                        childImageSharp {
                        fluid(quality: 90, maxWidth: 1920) {
                            ...GatsbyImageSharpFluid_withWebp
                            }
                        }
                    }
                }
            `}

            render={data => { Object.keys(data).map((image, i ) => {

                    console.log(props.stylesItem[image].name)
                    console.log(image)
                    return (
                        <Col md={4}>
                            <div class="style-box">
                                <StyledBackgroundImage
                                    Tag="div"
                                    className="style-box-img"
                                    fluid={data[image].childImageSharp.fluid}
                                >
                                </StyledBackgroundImage>
                                <div class="style-text-box">
                                    <h5 class="h5">{props.stylesItem[image].style}</h5>
                                    <h3 class="h3 style-description">{props.stylesItem[image].name}</h3>
                                    <div class="extra-style-details">
                                        <p class="style-short-desc">{props.stylesItem[image].tagline}</p>
                                        <p>{props.stylesItem[image].text}</p>
                                        <ul class="hashtag-list">
                                            <li class="style-attribut"></li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </Col>
                        )
                    })
                }
            }
        />
    )
}

export default StyleItem

const StyledBackgroundImage = styled(BackgroundImage)`
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
`

I'm passing in the following props to this component (abc dummy strings for better readability):

    stylesItem: {
            street: {
                style: "// STREET",
                name: "THE CANVAS",
                tagline: "abc",
                text: "abc",
                hashtags: [
                    "abc", "abc", "abc", "abc"
                ]
            },
            casual: {
                style: "// CASUAL",
                name: "THE CLASSIC",
                tagline: "abc",
                text: "abc",
                hashtags: [
                    "abc", "abc", "abc", "abc", "abc", "abc"
                ]
            },
            athletic: {
                style: "// ATHLETIC",
                name: "THE PERFORMER",
                tagline: "abc",
                text: "abc",
                hashtags: [
                    "abc", "abc", "abc", "abc", "abc", "abc"
                ]
            }
        }

I'm using Gatsby's Staticquery to load in 3 images (street, casual, athletic) and want to render the part in the second return statement 3 times (1 for each image), each time with the background image loading in dynamically as well as the content.

The 2 console.log() statements print out as expected.

console.log(props.stylesItem[image].name)
console.log(image)

THE CANVAS
street
THE CLASSIC
casual
THE PERFORMER
athletic

However nothing gets rendered to the screen and I'm not seeing any errors. What am I doing wrong?

Thanks in advance for your help


Solution

  • Your render prop on StaticQuery doesn't return anything, and therefore doesn't render anything.

    In the StaticQuery render prop you are mapping over the keys of the queried data, then generating a bunch of JSX successfully. But notice you are not actually doing anything with it because the resulting JSX doesn't get returned.

    So the entire StyleItem component does a bunch of work and then doesn't render anything, because the only thing it renders is StaticQuery.

    const StyleItem = ({ stylesItem }) => {
      return (
        <StaticQuery
          query={graphql`
            query {
              street: file(relativePath: { eq: "1.png" }) {
                childImageSharp {
                  fluid(quality: 90, maxWidth: 1920) {
                    ...GatsbyImageSharpFluid_withWebp
                  }
                }
              }
              casual: file(relativePath: { eq: "2.png" }) {
                childImageSharp {
                  fluid(quality: 90, maxWidth: 1920) {
                    ...GatsbyImageSharpFluid_withWebp
                  }
                }
              }
              athletic: file(relativePath: { eq: "3.png" }) {
                childImageSharp {
                  fluid(quality: 90, maxWidth: 1920) {
                    ...GatsbyImageSharpFluid_withWebp
                  }
                }
              }
            }
          `}
          render={data => {
            // Make sure to return something here
            return Object.keys(data).map(imageTitle => {
              const fluidProp = data[imageTitle].childImageSharp.fluid
              const imageData = stylesItem[imageTitle]
              return (
                <>
                  <StyledBackgroundImage
                    Tag="div"
                    className="style-box-img"
                    fluid={fluidProp}
                  ></StyledBackgroundImage>
                  <div>
                    <h5>{imageData.style}</h5>
                    <h3>{imageData.name}</h3>
                    <p>{imageData.tagline}</p>
                    <p>{imageData.text}</p>
                  </div>
                </>
              )
            })
          }}
        />
      )
    }
    

    Something worth nothing with Arrow functions is that

    when the only statement in an arrow function is return, we can remove return and remove the surrounding curly brackets

    (param1, param2, …, paramN) => expression  
    // equivalent to: => { return expression; }
    

    So the above render prop on StaticQuery could be further simplified as:

    render={data =>
      Object.keys(data).map(imageTitle => {...})
    }