Gatsby Dynamic Client Side Routes

Gatsby

Gatsby JS is a fantastic tool to build a react based static site. One of the primary tradeoffs when creating a React app and using its standard routing, is that you sacrifice initial page load speed and SEO for development convenience. Gatsby provides a way for you to have most of both of those benefits. 

Also, static site tools are trendy. All the other devs will think you are smart and that’s all that really matters right?

You can build a react based application, and still have the benefits of a “website” that’s built using html for each page (instead of each page being generated by javascript). Wow, that’s pretty neat!

The Challenge

One challenge of using a static site generator is when you eventually need to do something that falls slightly outside of what they were initially intended to do. That’s what this article covers. Gatsby generates your html ahead of time, each page is created beforehand. This is excellent when your content is well known beforehand. 

For example, let’s say you have a dynamic route in your application, /songs/:id, where the id is the id of the song from spotify. Imagine trying to generate a page of html beforehand for each possible id from spotify! How many songs are there? Like a bazillion. Your build server doesn’t even count that high. 

The Solution

Gatsby provides limited documentation on how to solve this problem. It does provide two tools that allow us to make this possible, but it doesn’t show you how to combine them. Gatsby uses reach router under the hood to do its routing, so we’re going to piggy back off of that. We will also customize the “gatsby-node.js” file to have it match client side routes the way we need to.

New Site

Create a new site with “gatsby new songs” to create a basic new site that we will test out this approach on.

Let’s take everything out of the component function on index.js and replace it with

pages/index.js

const IndexPage = () => (

 <Layout>

   <SEO title=“Home” />

   <p>Welcome to your Songs site!</p>

   <Link to=“/songs”>Go to the songs</Link>

 </Layout>

)



Now we need to create the page for listing out all of our songs. Let’s do that!

 

pages/songs.js

import React from “react”

import { Link } from “gatsby”

 

import Layout from “../components/layout”

import SEO from “../components/seo”

 

const songs = [

 {

   id: 1,

   name: “Falling”,

 },

 {

   id: 2,

   name: “Paranoid”,

 },

 {

   id: 3,

   name: “Mega Tubes”,

 },

 {

   id: 4,

   name: “Hey Jude”,

 },

 {

   id: 5,

   name: “Paralyzed”,

 },

]

const SongsPage = props => (

 <Layout>

   <SEO title=“Song Page” />

   <h1>Hi from the songs page</h1>

   <p>Welcome to the Songs page! ({props.path})</p>

   {/* Dynamic Links will go here */}

 </Layout>

)

 

export default SongsPage

 

 

 

So far, this is just static content. Now, let’s create some dummy songs. To keep this tutorial simple, we will just provide the data in a static manner instead of actually hooking up Spotify. The way we implement it will allow for the links to be dynamically generated on the client for whatever dynamic data you actually use to replace our static test data.

 

Add the following function to replace the comment in the SongsPage functional component

 

   {songs.map(song => (

     <Link style={{ display: “block” }} to={`/songs/${song.id}`}>

       {song.name}

     </Link>

   ))}

 

These links will not be functional yet and return a 404 because Gatsby has not created any pages/html for those ids. This is where the reach router comes in. 

The site should look something like this at this point

High Level Flow

Here’s a high level of what we’re going to try to accomplish. When the user makes a request for a route to ‘/songs/:id’ we’re going to route them to a new page we’re going to create in ‘pages/songs/song.js’. Once that page is loaded, the reach router is going to load a component we’ll create in ‘components/song.js’ that will take the incoming id and display it to the user.

Step 1

So, first, let’s customize Gatsby so that when someone makes any request that it matches the route /songs/:id it goes to the pages/songs/song.js component.

gatsby-node.js

exports.onCreatePage = async ({ pageactions }) => {

 const { createPage } = actions

 // page.matchPath is a special key that’s used for matching pages

 // only on the client.

 if (page.path.match(/^\/songs\/song/)) {

   page.matchPath = ‘/songs/*’

   // Update the page.

   createPage(page)

 }

}

Step 2

Now, we need to create the component that goes in pages/songs/song.js.

pages/songs/song.js

import React from “react”

import { Router } from “@reach/router” // included with gatsby

import SongComponent from “../../components/song”

import Layout from “../../components/layout”

export default function SongPage() {

 return (

   <Layout>

     <Router>

       {/* Tells client router to load the song component when the path matches /songs/:id */}

       <SongComponent path=“/songs/:id” />

     </Router>

   </Layout>

 )

}

Step 3

Finally, let’s create the SongComponent that lives at “/component/song.js”

component/song.js

import React from “react”

export default function SongPage() {

 return (

   <div>

     <p>Static Song content to be replaced</p>

   </div>

 )

}

For now, the content is static, but we can inform the component of the data using the reach router again and show the id of the song we want to use.

The id param is now part of the props being passed into the component thanks to the reach router so we can simply pull the id off the props and be on our merry way!

component/song.js

import React from “react”

export default function SongPage({ id }) {

 return (

   <div>

     <p>Static Song content to be replaced {id}</p>

   </div>

 )

}

Each song page should now look something like this

That’s it! You now have a static site with dynamic client side routes! Look at you. Your mother/father/role model/estranged spouse would be so proud!

Finished Working Repository

The story behind Go sounds a lot like the story behind other languages. 3 guys who worked at big company MegaCorp wanted a more effective way to run and write programs so they created the next great language.  You should use it so that you can have the best program on the block. 

What I’m still looking for is things about how it utilizes threads/processes and some of the bones behind the actual execution environment. I find this information critical to any production deployment. 

Their introduction is good but the website is a little bit difficult to read through. It reads a lot like java documentation from yesteryear https://golang.org/ 

Website | + posts