10/10

Article thumbnail

🔰 Integrating Zustand state management with Gatsby and React

7m
fullstack
full course
guide
tutorial

Intro

Integrate Zustand seamlessly into Gatsby & React for lightweight state management. Boost performance with an SEO-friendly guide for lightning-fast web development.

Why it's worth to use Zustand?

If you want to know the all course concepts, technologies and understand what kind of Node and npm versions you need, check the initial lesson - Course overview.

If you already read this article - jump into Gatsby5 | Tailwind | TypeScript | Cypress | jest and RTL template and check commits to understand the progress.

In previous lesson - 🌟 Organized Git commits with Commitlint, we configured Commitlint and we explored commits conventions. Now it's time to add Zustand for easy and lightweight state management.

Why do I want to use Zustand? To understand all reasons you should consider reading 🥇 Comparing Redux with Zustand for state management in React article, in which I'm comparing Zustand with Redux. However, if you don't have time I need to add here my reasons quickly:

  • it's super lightweight,
  • lack of boilerplate,
  • runtime fast and modular,
  • observable based,
  • well documented.

So, with this knowledge, it's time to configure Zustand for our Gatsby template project.

Installing Zustand

We need to start with a simple installation command in the terminal: npm i --save zustand. The new package will be added to our package.json file.

Loading

Querying page metadata with GraphQL

Let's say we want to query our home page metadata and assign it to Zustand store. The store doesn't exist yet, but we'll create it soon. We want to achieve it to avoid prop-drilling across many components that will be used on our page. So, firstly we need to create some GraphQL query in home page.

Loading

It's typical Gatsby stuff. We need some data from the file system or other sources and we're able to query it. In this case, we're getting information from gatsby.config.ts file i which we specify our site title and site URL in the following object.

Loading

Creating separate component for testing

To test our Zustand integration we need a component that will consume the store. Let's call it HomeView and let's add it inside the views/home/home.view.tsx file.

Loading

Now in our HomePage component which is pages/index.tsx file, we need to use our HomeView.

Loading

The title is now hardcoded but in the future, it will be taken from Zustand store. Before we continue, we need one more important stuff. We're using Tailwind in our project and we added the new directory in which we'll add our views components, so we need to update tailwind.config.js file.

Loading

If you are interested in why it's worthy to add separated components that group the view, see the following ⭐ Porting for React applications article.

Creating Zustand store and using it

Now it's time to create a Zustand store and attach it to our HomeView component. So, let's start with store and types definitions. Let's add the file store/home/home.store.ts.

Loading

We've added some types definitions for our state. It will have 2 possible shapes. The idle one which reflects nothing happened yet. It's just a temporary state to indicate the state between the server/client not happened yet.

The ready state reflects the situation in which we've data from server and data is synced with server/client.

Next, we created the store via create function and we passed type to this function to be protected by TypeScript. In addition, we created an initial state which is equal to is: "idle" object.

At the end, we added a custom selector hook that throws an error if we try to perform a read operation on the store when the state is idle. Why do we use this weird technique? The technique is called exhaustiveness checking and it will protect us from allocating not needed properties in objects and will guide us by hand when we try to access these properties.

But why we're throwing an exception? Imagine a situation when you will use a page, query the data with GraphQL, and want to assign this data to Zustand store to be able to consume it in nested components. If you forget to do a sync (this we still need to implement), there is a risk that data may not exist yet. To be able to find this problem faster we're throwing an exception.

Ok, we have a store, so now we need to use it in our HomeView component.

Loading

Syncing the state with a custom hook

There is still one missing important part - sync between the client and server state injected when we run the build process in Gatsby. Unfortunately, we need to write this logic on our own. The custom hook will be perfect for this case. Let's call it useStoreSync and add it to development-kit/use-store-sync.ts file.

Loading

To sync the state between server/client we need to:

  1. pass the default state (taken from GraphQL query),
  2. set this state as default one,
  3. check if it is a server or not,
  4. if it is a server - we need to create a store once and return it,
  5. if it's a client we need to set state as the passed one.

Our hook now may be used in HomePage component - the pages/index.tsx file, in the following way:

Loading

We've passed here the useHomeStore instance and the initial state to set. Now our hook will do whole meat and the state will be the same during build process for nested components and after rehydrating on the client side!

Interested about more details and how to do it in NextJS? Feel free to dive through 🌟 How to integrate state management in Zustand with NextJS article.

The result

Our Zustand is attached to Gatsby ecosystem! Now when you inspect the dev tools you'll see that initially generated HTML during build process is the same as the one created by the client later.

Loading

The final result

To get current result jump into Gatsby5 | Tailwind | TypeScript | Cypress | jest and RTL template and check commits to understand the progress.

Conclusions and next steps

Now, we are able to avoid prop drilling with a simple utility hook call at the beginning of the page. The best part is that this hook will work also in NextJS for server components and statically generated/server-side rendered pages.

If you want to check how just go to 🌟 How to integrate state management in Zustand with NextJS article.

In the next lesson, we'll configure page generator and view templates.

I create content regularly!

I hope you found my post interesting. If so, maybe you'll take a peek at my LinkedIn, where I publish posts daily.

Comments

Add your honest opinion about this article and help us improve the content.

10/10

created: 25-09-2023
updated: 06-12-2023