E-Commerce for React Developers [w/ Gatsby Tutorial]

In a rush? Jump to technical tutorial or live demo.

Developers should be able to use any stack, whether they're building e-commerce or not.

☝️ That was the initial promise behind our developer-first shopping cart.

One we've kept for 5 years now.

Turns out 2018 stacks are more frontend-centric than ever, with React leading the pack.

With that in mind, I thought I'd craft a thorough piece on React e-commerce for developers.

In this post, I'll explore how React and e-commerce can go hand-in-hand—with its multiple benefits & tools.

Then, I’ll go to full-on tutorial mode, showcasing my handcrafted React store using Gatsby.

gatsby

Steps 🛠️

  1. Creating a Gatsby site
  2. Generating & defining products
  3. Integrating a shopping cart to Gatsby
  4. Leveraging React components
  5. Deploying the site to Netlify

Okay, let’s do this!

Should you use React for e-commerce?

If you’re here, you probably don’t need an introduction to React at this point.

It has been at the forefront of frontend web development for a few years now. It boasts a constellation of stars at the top of its GitHub repo. It’s used by tech behemoths like Airbnb, Netflix, and Instagram.

It was created by Facebook developers for Pete’s sake! Saying it’s trendy is an understatement.

Image from The State of JavaScript 2018: React’s in good shape.

Image from The State of JavaScript 2018: React's in great shape.

But trendy isn’t a synonym for overrated. React has proven its awesomeness more than enough. With its component-centric development, Virtual DOM, JSX syntax, etc. it has changed frontend development for the best.

But the real question here is: “Is it any good for e-commerce?”

It can be great, as long as you’re willing to get your hands dirty (coding-wise).

As developers, the fun isn't in being told by restraining, monolithic systems what tech to use and how. It's in choosing ourselves the right tools for the right job. JS frameworks, static sites & the JAMstack gave the freedom back to developers to create kickass UX by themselves.

Plus, the features of a framework like React will translate into benefits for clients as well.

The use of components for flexibility.

Component-based development enables easy code reuse through your app, but also the writing of small features. Or, in our case, small e-commerce functionalities. This comes in handy once you start scaling and expanding your shopping cart integration. I’ll show you a concrete example in the demo further down.

Virtual DOM for performance.

React’s virtual DOM provides a more efficient way of updating the view in a web application. Performance is HUGE in e-commerce; every milli-seconds count. Speed = Better UX/SEO = $$$.

Don’t let gossip about React SEO issues fool you; there are many ways to make your React apps SEO-friendly.

Popularity & vast community for peace of mind.

If you’re a merchant, it shouldn’t be too hard finding developers to maintain your React e-commerce app. If you’re a developer, any issue has probably already been documented. Also, the ecosystem has spawned dozens of excellent dev tools to optimize React development.

Let's say you’ve decided React’s the right choice for your online store. Where do you go from there?

A look at React e-commerce tools 🛒

A couple solutions will let you kickstart your e-commerce development with React:

  • Moltin - An API-based e-commerce solution. It allows you to use React natively to power your applications.
  • Cezerin - A React & Node.js-based e-commerce platform. Enables the creation of PWAs.
  • Reaction Commerce - Open-source, real-time platform. Built on Node.js, but plays nice with React.

There are also a few frontend platforms into which you can integrate e-commerce functionalities, like Next.js, a lightweight framework for static and server-rendered apps.

The one I’ve chosen for this post? Gatsby. I’ll integrate it with our shopping cart for developers, Snipcart. Result should be a neat, React-powered e-commerce app!

What is Gatsby?

Gatsby is a static website generator built with innovative web technologies such as React and Webpack.

gatsby-react

It supports Markdown, HTML, and React components out of the box. It's also easy to add support for additional file types like SCSS, for instance.

The truth is, since the first iteration of this post, Gatsby has become way more than a static site generator. As a matter of fact, it’s now a go-to solution to build progressive web apps in React.

It now also comes with a feature that makes it easy to query Gatsby's API with GraphQL, and I strongly recommend this tutorial if you ever want to use it with headless CMSs, databases or APIs.

In short, Gatsby is fantastic and quickly finding its way up the ladder of popular SSGs.

But let’s not get ahead of ourselves right now. In this post, I’ll use it for static site generation & a simple shopping cart integration. Still, I’ll try to throw in some of the more advanced Gatsby features—like GraphQL—to push e-commerce functionalities further.

React e-commerce tutorial: crafting a Gatsby store

react-gatsby-ecommerce

Pre-requisites

  • A Snipcart account (forever free in Test mode)
  • Basic JavaScript & React knowledge

1. Powering up your new Gatsby website

First, you need to install the generator itself:

npm install -g gatsby

For this example, I decided to use gatsby-starter-blog. It offers articles iteration on the front page and a single page for all items. Exactly what I needed for my demo products.

Go on and run:

gatsby new snipcart-gatsby-integration https://github.com/gatsbyjs/gatsby-starter-blog

Once it’s done, hit gatsby develop and you're good to go. You should have a running website on localhost:8000 with react-hot-loader functionalities.

Then, open the project in your favorite IDE. If you're currently developing a website that will hit production, you'll want to open the gatsby-config.js file first to make sure the siteMetadata is defined according to your information. If not, you can ignore this.

2. Creating and defining products

Let's add some products under the src/pages/ folder.

First, delete the folders already in there and create one new folder per product with an index.md inside:

/pages/bow-ties/index.md

---
title: Bow Ties
layout: post
date: 2018-07-21
id: 2
price: 7.00
image: "bow-ties"
path: "/bow-ties/"
description: "The bow-tie (not to be confused with the tae bo) is an aphrodisiac worn by male humans attempting to win one or more mates."
---

> The bow-tie (not to be confused with the tae bo) is an aphrodisiac worn by male humans attempting to win one or more mates. According to scientists (many of whom sport the style regularly), the bow-tie has been clinically proven to yield positive results. These findings were confirmed by the surge in popularity of the ties in the 1960's which led to a nation-wide public school banning. ([source](http://uncyclopedia.wikia.com/wiki/Bow_tie))

/pages/dry-martini/index.md

---
title: Dry Martini
layout: post
date: 2018-07-21
id: 3
price: 8.50
image: "dry-martini"
path: "/dry-martini/"
description: "The taste of excellence."
---

> "One Martini is all right. Two are too many, and three are not enough."

/pages/fireworks/index.md

---
title: Fireworks
layout: post
date: 2018-07-21
id: 1
price: 67.89
image: "fireworks"
path: "/fireworks/"
description: "Fireworks are a noble, traditional way to emphasize the greatness of an event."
---

> Fireworks are a noble, traditional way to emphasize the greatness of an event. They command the epic. They are poetry in a dark night sky. They look good, smell strong, and are dangerous to play with. A bit like secret agents.

3. Integrating a shopping cart into your static Gatsby site

Open the templates/blog-post.js file. That's where we're going to put Snipcart's specific scripts.

More precisely, you’ll insert them inside the Helmet component, a neat little component for your document's head management.

The necessary snippets of code can be found under the API keys section of your Snipcart admin dashboard.

Redefine the component as follows:

<Helmet
htmlAttributes={{ lang: 'en' }}
meta={[{ name: 'description', content: siteDescription }]}
title={siteTitle}
link={[{
  href:"https://cdn.snipcart.com/themes/2.0/base/snipcart.min.css",
  rel:"stylesheet",
  type:"text/css" 
}]}
script={[{ 
  type: 'text/javascript', 
  url:"",
  id: "snipcart",
  "data-api-key": "YjdiNWIyOTUtZTIyMy00MWMwLTkwNDUtMzI1M2M2NTgxYjE0",
  src:"https://cdn.snipcart.com/scripts/2.0/snipcart.js" 
},{
  type: 'text/javascript',
  src:"https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"
}]} />

Now, let's customize the templates a bit and add some Snipcart buy buttons into the mix.

Again, pop up the templates/blog-post.js file. That's the template that is going to be used for each product page.

Go straight at the bottom and find the pageQuery const. This is a GraphQL query. Gatsby uses it to define a way of fetching information when building your website.

You’ve added some non-standard frontmatter earlier when you defined new products, and you now need to add these fields in the query to get the new information.

Do so by simply redefining the query as follows:

export const pageQuery = graphql`
      query BlogPostBySlug($slug: String!) {
        site {
          siteMetadata {
            title
            author
          }
        }
        markdownRemark(fields: { slug: { eq: $slug } }) {
          id
          excerpt
          html
          frontmatter {
            title
            date(formatString: "MMMM DD, YYYY")
            price
            id
            path
            description
            image
          }
        }
      }
    `

Now, you have access to our new products information, so let's use it in your template. In my case, I added a picture and a buy button and deleted the Bio component used at the end of the page.

Here's what I have just after the first <p>:

<a 
    href='#' 
    className='snipcart-add-item'
    data-item-id={post.id}
    data-item-price={post.price}
    data-item-image={post.image}
    data-item-name={post.title}
    data-item-description={post.description}
    data-item-url={"http://snipcart-gatsby.netlify.com" + post.path}>
    Buy
</a>

<img src={imgSrc}></img>

<div dangerouslySetInnerHTML={{ __html: post.html }} /> 

<a
    href='#' 
    className='snipcart-add-item buyBtn'
    data-item-id={post.frontmatter.id}
    data-item-price={post.frontmatter.price}
    data-item-image={post.frontmatter.image}
    data-item-name={post.frontmatter.title}
    data-item-description={post.frontmatter.description}
    data-item-url={"http://snipcart-gatsby.netlify.com" + post.frontmatter.path}>
    Buy
</a>

4. Leveraging React components

Now you have a homepage showcasing all your products with individual pages for each of them. Let's push the integration a bit further and add some custom fields to your products.

Let’s also create a custom react component to handle these custom fields out of the cart so that when a product is added to it, the proper custom field option is already selected.

First things first: adding custom fields to your products. To do so, add a new field to your products frontmatter, namely "customFields". We’ll also refactor our image field to include multiple images.

You’ll end up with the following frontmatter structure:

---
title: Bow Ties
layout: post
date: 2018-07-21
id: 2
image:
  - name: 'Blue Red'
  src: 'blue-red'

  - name: 'White Blue'
  src: 'white-blue'

  - name: 'White Gray'
  src: 'white-gray'
price: 7.00
path: "/bow-ties/"
customFields:
  name: Color
  values: ['Blue Red', 'White Blue', 'White Gray']
description: "The bow-tie (not to be confused with the tae bo) is an aphrodisiac worn by male humans attempting to win one or more mates."
---

> The bow-tie (not to be confused with the tae bo) is an aphrodisiac worn by male humans attempting to win one or more mates. According to scientists (many of whom sport the style regularly), the bow-tie has been clinically proven to yield positive results. These findings were confirmed by the surge in popularity of the ties in the 1960's which led to a nation-wide public school banning. ([source](http://uncyclopedia.wikia.com/wiki/Bow_tie))

I was pretty hyped about React's Hooks API announcement and decided to play around with it in this post, even though it's still in alpha.

You could write the component with a traditional class, but Hooks "[...] let you use state, and other React features without writing a class."

It’s perfect for the small component you’re about to create—you get the power of React without the boilerplate coming with classes.

To use the alpha, you'll need to run npm install react@16.7.0-alpha.2 and npm install react-dom@16.7.0-alpha.2.

You’ll also have to change the GraphQL query to include our new customFields & image fields.

Here's how it looks at this point:

export const pageQuery = graphql`
    query BlogPostBySlug($slug: String!) {
    site {
        siteMetadata {
        title
        author
        }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
        id
        excerpt
        html
        frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
        price
        id
        path
        description
        image {
            name
            src
        }
        customFields { 
            name
            values 
        }
        }
    }
    }
`

Hop in the components folder and create a BuyButton.js file.

Inside it, write:

import React, { useState } from 'react';

var BuyButton = React.memo(({post, images}) => {
    const [selected, setSelected] = useState(post.customFields.values[0]);
    var filteredImgs = images.filter(x => x.name == selected);
    var choosenImgSrc = filteredImgs.length > 0
    ? filteredImgs[0].src
    : images[0].src

    return (
    <div>
        <img src={choosenImgSrc} width="400px"></img>
        <h3>{post.customFields.name}</h3>
        <select 
            id={post.customFields.name} 
            onChange={(e) => setSelected(e.target.value)} 
            value={selected}
            style={{
                borderRadius: "5px",
                paddingRight: "20px",
                paddingBlockStart: "13px",
                paddingBlockEnd: "13px",
                marginRight: "15px"
            }}>
            {post.customFields.values.map((x) => (<option key={x}>{x}</option>))}
        </select>

        <a
        style={{
            backgroundColor: "#212121",
            borderRadius: "5px",
            color: "#F5F5F5",
            fontWeight: "bold",
            paddingBottom: "15px",
            paddingTop: "15px",
            paddingRight: "35px",
            paddingLeft: "35px",
            fontSize: "24"
        }}
        id="buyButton"
        href='#' 
        className='snipcart-add-item buyBtn'
        data-item-id={post.id}
        data-item-price={post.price}
        data-item-image={choosenImgSrc}
        data-item-name={post.title}
        data-item-description={post.description}
        data-item-custom1-name={post.customFields.name}
        data-item-custom1-value={selected}
        data-item-url={"https://snipcart-react-gatsby.netlify.com/" + post.path}>
        Buy for {post.price}$
    </a>
    </div>
    )
})

export default BuyButton;

What you just did here is taking the buy button and putting it inside the new component. All while using React, but without defining any class. That’s what the Hooks are all about.

The React.memo call is only there to make everything work with the HotReload development module. Since Hooks are still in alpha, this acts like a little patch for the moment. Thanks to the hook, the logic is pretty barebones— no overhead, only a state field.

This small state field is instantiated using the useState utility provided by React. It returns the current state (selected), and a function updates the state (setSelected). You then use these to show the proper state and update it when a change occurs.

The buy button custom field attribute is defined directly with the selected value. You don't need anything else (like jQuery). Once the state changes, it initiates a rerender as usual, and the buy button will reflect the new state. This is also why we can neatly update the image based on the selected value of the custom field.

Now, let's jump back in the templates/blog-post.js file, and refactor it to use our new component.

Import the new component with:

import BuyButton from '../components/BuyButton'

Then, you’ll have to declare an images variable to require the images in the right format. You can declare it as the first line of your render function:

const images = post.frontmatter.image
        .map(x => ({
        name: x.name,
        src: require(`./../pages${post.frontmatter.path}${x.src}.jpg`)
        }))

To finish, you’ll have to replace the whole previous buy button declaration with a simple:

<BuyButton post={post.frontmatter} images={images}>
</BuyButton>

5. Deploying our store using Netlify

We've deployed a few static site e-commerce projects using the killer hosting platform that is Netlify. In a nutshell, Netlify is a quality CDN-based hosting service streamlining builds, deploys and hosting for static sites. Developers dig it, and so do we!

Check out their quickstart documentation.

I ended up running these:

npm install netlify-cli -g
netlify init
netlify update -n snipcart-gatsby
netlify deploy 

That’s it; your static e-commerce site’s already deployed! :)

Witness Gatsby’s greatness

Enjoy the Great Gatsby’s legendary hospitality & let the party begin!

gatsby-ecommerce-demo

See the live demo here.

See the GitHub repo here.

Closing thoughts

I spent around two hours building a fully functional React e-commerce app with Gatsby. Here are my takeaways from working with this framework.

The stuff I enjoyed

  • Overall, Gatsby's fun to work with. The stack is exciting and makes good use of some of the latest—and awesome—web technologies.
  • Using the command-line tool is simple enough.
  • The "Starters" available on GitHub are a lovely touch to kickstart projects.
  • It's easy to use, learn and customize.

The stuff I enjoyed a bit less

  • React hooks are still in alpha, and I had to try a bunch of different things to make it work with the hot module replacement.
  • I always had quite mysterious issues when trying to load the images using require. In the end, it had to do with Gatsby cache - I think - it might be good to restart your dev server if you stumble on such issues.

I hope this post inspired you to play around a bit with React and Gatsby, and maybe even start a modern static project. You could also consider throwing some decoupled content management in there with a headless CMS.


If you've enjoyed this post, please take a second to share it on Twitter. Got comments, questions? Hit the section below!

Suggested posts: