Passing Props between Layout and Children in Gatsby with useContext

Gatsby-plugin-layout is a great way to have a persistent layout component that stays mounted between pages, but what if we also want to pass props from our layout to pages/components and vice-versa? There are a few ways to go about it, but on a recent smaller project I opted for React Context. Note: this article will assume you already have gatsby-plugin-layout added to your project — if not, don’t worry! It’s super simple, just head over to their github for instructions.

The first step is adding a file to store our data in. In your components folder, create a file called store.js and import createContext, useContext, and useState (along with React, of course). Next, for every state you want stored between pages, create a new context for both reading & updating that individual state. Here’s what that looked like in my project:

It looks like a lot, but having a context for each action actually improves performance by preventing unnecessary re-renders.

Now, to make accessing each context simpler in our pages/components, we’re going to create a useItemContext wrapper for each one. This wrapper will call the useContext hook and also throw an error message if we attempt to use it outside of our main ContextProvider.

Do this for each of the contexts you create.

Now to create our main ContextProvider. This is what we’ll wrap our layout component with, and where we’ll store the actual state we want to read/manipulate. In my ContextProvider, I started by defining the most simple state, menu. This is just a boolean that I’ll be toggling true/false.

Make sure to also pass children to your ContextProvider.

Next, for entered I had another boolean, but also wanted a couple additional things to happen when it gets toggled to true.

Finally, for song I had my most complicated state to maintain (basically just a variety of strings). In this case, we’ll need to import useReducer to read/write the song context. Most of the details can be ignored — all you really need to know is that we’re defining the initialState, assigning state (our read method) and dispatch (our write method) to useReducer, and using a switch statement inside the reducer to manipulate state depending on what we pass in. Make sure to also pass in initialState at the end as our initial argument.

Now we can finally create the return value of our ContextProvider component. We’re going to return each ItemContext.Provider along with a value attribute, which will be either the current state of that item, a method to update the state, or (in the case of SongContext) both.

Time to start using our ContextProvider. Head over to your layout.js component and wrap the whole thing with your ContextProvider. Now every component/page rendered will have access to our context. Here is what using that context looks like for menu, the simple boolean I created.

Now I can call menu to read the state, and () => toggleMenu(!menu) to change it.

In the case of song (which has both the read and write method in one), we’ll be destructuring state to read the current song, and dispatch to change the current song.

Read method in action.
Write method in action.

And that’s it for implementing useContext with gatsby-plugin-layout. This was my first time using React Context in general but has been working great for me so far — leave a comment if you notice any issues or room for improvement!

Frontend Developer/UI Designer in Austin, TX

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store