Joel M. Turner

Illustration

Blog

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

This post is part of the Create an Avatar Component in Gatsby with TypeScript series

Part 1: We'll build the simple react componentPart 2: We'll start hooking up Gatsby imagePart 3: We'll type it with TypeScript

In Part 1 we put together a simple avatar component that can receive an image url and render it out as a round 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

1npm install --save gatsby-image

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

1npm install --save gatsby-transformer-sharp gatsby-plugin-sharp

Then in your gatsby-config.js:

1plugins: [`gatsby-transformer-sharp`, `gatsby-plugin-sharp`]

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

1const path = require(`path`)
2
3module.exports = {
4 plugins: [
5 {
6 resolve: `gatsby-source-filesystem`,
7 options: {
8 name: `assets`,
9 path: path.join(__dirname, `src`, `assets`),
10 },
11 },
12 `gatsby-plugin-sharp`,
13 `gatsby-transformer-sharp`,
14 ],
15}

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 so the browser doesn’t have to do all the work.

1const data = useStaticQuery(graphql`
2 query {
3 placeholderImage: file(relativePath: { eq: "monster-01-headshot.png" }) {
4 childImageSharp {
5 fixed(width: 75, height: 75) {
6 ...GatsbyImageSharpFixed
7 }
8 }
9 }
10 }
11 `)

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

1import Img from "gatsby-image"
2
3function Avatar(props) {
4 {...}
5 return (
6 <Img
7 style={styles}
8 fixed={data.placeholderImage.childImageSharp.fixed}
9 alt={altText}
10 title={title} />
11 )
12}

Now let’s put it all together.

1import React from "react"
2import { useStaticQuery, graphql } from "gatsby"
3import Img from "gatsby-image"
4
5function Avatar(props) {
6 const data = useStaticQuery(graphql`
7 query {
8 placeholderImage: file(relativePath: { eq: "monster-01-headshot.png" }) {
9 childImageSharp {
10 fixed(width: 75, height: 75) {
11 ...GatsbyImageSharpFixed
12 }
13 }
14 }
15 }
16 `)
17
18 const {url, altText, title} = props;
19 const styles = {
20 width: '75px',
21 height: '75px',
22 borderRadius: '50%'
23 }
24
25 return (
26 <Img
27 style={styles}
28 fixed={data.placeholderImage.childImageSharp.fixed}
29 alt={altText}
30 title={title} />
31 )
32}
33
34export default Avatar

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.

1import React from "react"
2import { useStaticQuery, graphql } from "gatsby"
3import Img from "gatsby-image"
4
5function Avatar(props) {
6 const data = useStaticQuery(graphql`
7 query {
8 placeholderImage: file(relativePath: { eq: "monster-01-headshot.png" }) {
9 childImageSharp {
10 fixed(width: 75, height: 75) {
11 ...GatsbyImageSharpFixed
12 }
13 }
14 }
15 }
16 `)
17
18 const {url, altText, title} = props;
19 const styles = {
20 width: '75px',
21 height: '75px',
22 borderRadius: '50%'
23 }
24
25 if (url) {
26 return (
27 <img
28 style={styles}
29 src={url}
30 alt={altText}
31 title={title} />
32 );
33 }
34
35 return (
36 <Img
37 style={styles}
38 fixed={data.placeholderImage.childImageSharp.fixed}
39 alt={altText}
40 title={title} />
41 )
42}
43
44export default Avatar

This allows us to call avatar without us needing to pass a prop of 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:

1function Avatar(props) {
2 const data = useStaticQuery(graphql`
3 query {
4 monster1: file(relativePath: { eq: "monster-01-headshot.png" }) {
5 childImageSharp {
6 fixed(width: 75, height: 75) {
7 ...GatsbyImageSharpFixed
8 }
9 }
10 }
11 monster2: file(relativePath: { eq: "monster-02-headshot.png" }) {
12 childImageSharp {
13 fixed(width: 75, height: 75) {
14 ...GatsbyImageSharpFixed
15 }
16 }
17 }
18 }
19 `)
20
21 const {url, altText, title, user} = props;
22 const image = data[user].childImageSharp.fixed;
23 {...}

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

1<Avatar
2 alText='Monster P. Whittington portrait'
3 title='Monster P. Whittington'
4 user='monster1' />
1<Avatar
2 alText='Mons T. Cobblepot portrait'
3 title='Mons T. Cobblepot'
4 user='monster2' />

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.

Discuss this article on Twitter