DEV Community

Jordan Jones.
Jordan Jones.

Posted on

Building a slideshow with Gatsby-Image and React Hooks

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!

Oldest comments (5)

Collapse
 
vidomarkas profile image
Viktoras Domarkas

Good job, Jordan! Thanks

Collapse
 
mirceavld profile image
Mircea

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

Collapse
 
ashadnasim52 profile image
ashad nasim

awesome content

Collapse
 
ilialuk profile image
Ilia luk

NICE! works like a charm!

Collapse
 
rudolfhans profile image
Rudolf Hans

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