loading...

Building a slideshow with Gatsby-Image and React Hooks

pr0x1ma profile image Jordan Jones. ・3 min read

image

GatsbyJS is one of my favourite technologies lately, It has made frontend development enjoyable again, but I've encountered some limitations (Not specific to Gatsby)
recently and it seems others have encountered similar issues. Namely, building a slideshow/carousel/multiple images with
gastbyjs and gatsby-image.

TLDR; I built a "slideshow" of lazy loaded images, demo over at gatsby-slides

Disclaimer: This is pretty experimental and hacky and I'm fairly certain it can be improved, critiques are welcome.

Set up Gatsby and Gatsby-Image

Because gatsby docs are so well done, it's fairly easy to get started and set up with a basic project. From your terminal, type

$ gatsby new gatsby-slide
$ cd gatsby-slide

This creates a new gatsby project (with gatsby-image already installed) from a starter template and changes directory after gatsby is done setting up files.

Now if we run npm start and navigate to localhost:8000 we should see our gatsby site up and running.

We're all set to continue!

Querying Multiple Images

So thankfully, the template includes code to already query an image as shown below

//src/image.js

const Image = () => (
  <StaticQuery
    query={graphql`
      query {
        placeholder: file(relativePath: { eq: "gatsby-logo.png" }) {
          childImageSharp {
            fluid(maxWidth: 300) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    `}
    render={data => <Img fluid={data.placeholder.childImageSharp.fluid} />}
  />
)

This finds the image gatsby-logo.png and lazy loads it with the
fragment GatsbyImageSharp, read more about fragments and gatsby-image here. But how do we
use this to query multiple images? I came across this lil gem while reading the other day, thanks to Kent C. Dodds for writing it.

graphql`
  query {
    allFile(
      sort: { fields: name, order: DESC }
      filter: { relativeDirectory: { eq: "slides" } }
    ) {
      edges {
        node {
          id
          name
          childImageSharp {
            fluid(maxWidth: 600) {
              ...GatsbyImageSharpFluid_withWebp_tracedSVG
            }
          }
        }
      }
    }
  }

Now that we have this query for getting multiple files, let's go ahead and wire this up with good ol hooks.

import { useStaticQuery, graphql } from 'gatsby'

function SlideShow() {
  const [index, setIndex] = useState(0)
  const { allFile } = useStaticQuery(
    graphql`
      query {
        allFile(
          sort: { fields: name, order: DESC }
          filter: { relativeDirectory: { eq: "slides" } }
        ) {
          edges {
            node {
              id
              name
              childImageSharp {
                fluid(maxWidth: 600) {
                  ...GatsbyImageSharpFluid_withWebp_tracedSVG
                }
              }
            }
          }
        }
      }
    `
  )
  //Minus 1 for array offset from 0
  const length = allFile.edges.length - 1
  const handleNext = () =>
    index === length ? setIndex(0) : setIndex(index + 1)
  const handlePrevious = () =>
    index === 0 ? setIndex(length) : setIndex(index - 1)
  const { node } = allFile.edges[index]
  return (
    <div>
      <div>
        <Img
          fluid={node.childImageSharp.fluid}
          key={node.id}
          alt={node.name.replace(/-/g, ' ').substring(2)}
        />
      </div>
      <div>
        <button onClick={() => handlePrevious()}>Previous</button>
        <button onClick={() => handleNext()}>Next</button>
      </div>
    </div>
  )
}

Some additional logic for handling next and previous slide but overall still a simple example.

Conclusion

Through the mystical powers of React Hooks and graphql, we can useStaticQuery hook as well
as specifying a filter on our allFiles to query to get all images in the slides folder (where all the images for the slideshow are, duh Jordan). The result is pretty niffy, check out the demo gatsby-slides.

Did this interest you? Head over to jordnjones.com for more!

Posted on by:

pr0x1ma profile

Jordan Jones.

@pr0x1ma

Fullstack JS developer based in Kingston, Jamaica

Discussion

markdown guide
 

Thank you Jordan, exactly what I was looking for.
One thing doesn't work for me, maybe someone had a similar issue.
I have three images in my slider. Clicking "next" on the last one, the whole pages goes white and the silder doesn't start from the first image again.
I'm importing the silder as a component into a page.
Help with this is much appreciated.
Thanks

 
 

Nice one Jordan. Until now, I just used Pixteller to create slideshows. But I'll try your code.