DEV Community

loading...
Cover image for Create an Avatar Component in Gatsby with TypeScript: Part 2 – Gatsby Image

Create an Avatar Component in Gatsby with TypeScript: Part 2 – Gatsby Image

Joel Turner
I'm a kombucha lovin' Front-End Dev at Sprinklr. Love lettering, love design, love development, love Portland. Husband, father. He/Him
Originally published at joelmturner.com on ・3 min read

In Part 1 we put together a simple avatar component that can receive an image URL and render it out as around image.

To get the full benefit of Gatsby Image we need to make sure our image is pulled into our graphql. We'll need to install a couple of plugins to help us here. gatsby-image, gatsby-transformer-sharp, gatsby-plugin-sharp will be needed.

Let's install gatsby-image

npm install --save gatsby-image
Enter fullscreen mode Exit fullscreen mode

Then, if you don't already have gatsby-transformer-sharp and gatsby-plugin-sharp we can install them.

npm install --save gatsby-transformer-sharp gatsby-plugin-sharp
Enter fullscreen mode Exit fullscreen mode

Then in your gatsby-config.js:

plugins: [`gatsby-transformer-sharp`, `gatsby-plugin-sharp`]
Enter fullscreen mode Exit fullscreen mode

We'll need a source plugin set up as well. For this example, we're going to use gatsby-source-filesystem. Here is what our gatsby-config might look like, assuming our images are in src/assets.

const path = require(`path`)

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `assets`,
        path: path.join(__dirname, `src`, `assets`),
      },
    },
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
  ],
}
Enter fullscreen mode Exit fullscreen mode

Now let's drop our image file into our assets folder and create a query for it. We can use the hook for StaticQuery in our component which will make the image available through the data prop. Since we know the size of the image we can add those dimensions in our graphql query so the browser doesn't have to do all the work.

  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "monster-01-headshot.png" }) {
        childImageSharp {
          fixed(width: 75, height: 75) {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `)
Enter fullscreen mode Exit fullscreen mode

Then we need to add the Img component from gatsby-image so that it can do its magic.

import Img from "gatsby-image"

function Avatar(props) {
  {...}
  return (
    <Img
      style={styles}
      fixed={data.placeholderImage.childImageSharp.fixed}
      alt={altText}
      title={title} />
  )
}
Enter fullscreen mode Exit fullscreen mode

Now let's put it all together.

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"

function Avatar(props) {
  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "monster-01-headshot.png" }) {
        childImageSharp {
          fixed(width: 75, height: 75) {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `)

  const {url, altText, title} = props;
  const styles = {
    width: '75px',
    height: '75px',
    borderRadius: '50%'
  }

  return (
    <Img
      style={styles}
      fixed={data.placeholderImage.childImageSharp.fixed}
      alt={altText}
      title={title} />
  )
}

export default Avatar
Enter fullscreen mode Exit fullscreen mode

We're still missing the ability to pass a URL to our avatar component so let's add that back in. We can return a regular img element if we get a URL. Using fixed will be better since we're not worried about fluid mode with this component.

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"

function Avatar(props) {
  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "monster-01-headshot.png" }) {
        childImageSharp {
          fixed(width: 75, height: 75) {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `)

  const {url, altText, title} = props;
  const styles = {
    width: '75px',
    height: '75px',
    borderRadius: '50%'
  }

  if (url) {
    return (
      <img
        style={styles}
        src={url}
        alt={altText}
        title={title} />
    );
  }

  return (
    <Img
      style={styles}
      fixed={data.placeholderImage.childImageSharp.fixed}
      alt={altText}
      title={title} />
  )
}

export default Avatar
Enter fullscreen mode Exit fullscreen mode

This allows us to call avatar without us needing to pass a prop of the image URL. If you need multiple avatar images for your team you can add them to the quite and pass a user prop down and we'll grab that from the query. We can name the queries to match the users like so:

function Avatar(props) {
  const data = useStaticQuery(graphql`
      query {
        monster1: file(relativePath: { eq: "monster-01-headshot.png" }) {
          childImageSharp {
            fixed(width: 75, height: 75) {
              ...GatsbyImageSharpFixed
            }
          }
        }
        monster2: file(relativePath: { eq: "monster-02-headshot.png" }) {
          childImageSharp {
            fixed(width: 75, height: 75) {
              ...GatsbyImageSharpFixed
            }
          }
        }
      }
    `)

  const {url, altText, title, user} = props;
  const image = data[user].childImageSharp.fixed;
  {...}
Enter fullscreen mode Exit fullscreen mode

That way we can pass monster1 or monster2 in our user prop to have it render that monster.

<Avatar
    alText='Monster P. Whittington portrait'
    title='Monster P. Whittington'
    user='monster1' />
Enter fullscreen mode Exit fullscreen mode
<Avatar
    alText='Mons T. Cobblepot portrait'
    title='Mons T. Cobblepot'
    user='monster2' />
Enter fullscreen mode Exit fullscreen mode

Nice, now we can type it so it's easier to know what name can be used and to see if our structure is correct if we ever need to edit it.

Discussion (1)

Collapse
attkinsonjakob profile image
Jakob Attkinson

Thanks for the tutorial!
While part 1&2 were clear and straightforward, I fail to understand what the 3rd part is about and when/why is needed.

Would you, please, take a minute to explain me this part (like I'm five)?
I don't event get why Graphql is necessary here...

I'll soon follow through with my implementation of your tutorial.

P. S. I'm (very) new to react and gatsby.