Sharing state between Astro + React components using zustand stores for smooth and SaaSy UX

Kevin Firko

You can use the popular zustand state management library to enable Astro, React, and other “framework components” to share state via zustand stores.

I put together a demo and example GitHub repository when I couldn’t find anything out there that showed how it could be done.

While I was able to find an awesome example (with a live demo on Stackblitz) of React, Vue, Solid, Svelte, and Preact components sharing a zustand store while being rendered as islands within an Astro app… Astro components themselves were not included!

Check out my demo of Astro and React components sharing state via a common zustand store:

In future when ChatGPT and other LLMs can give reasonably accurate answers about how to do this and spit out an example without making laughable mistakes, you’ll know where the training data they’re regurgitating came from!

Importance of Shared State

Astro is rapidly evolving into a full-stack framework (and more!). A growing suite of optional server-driven features launch its capabilities far beyond the static site generator it was originally conceived as and continues to excel at.

To create a smooth, modern, app-like UX with Astro it is important for layouts and components in disparate islands to stay in sync on the client-side and operate together as a single cohesive UI.

This is not typically a significant concern for the primarily content-driven static sites that Astro was first designed for such as blogs, marketing, and docs sites.

Astro as an app framework

Creating a cohesive app UI presents more of a challenge because Astro layouts, pages, and components are combined with components written in React, Vue, Svelte, Solid, etc. and must work together as one dynamic UI.

In app projects Astro generally serves as the “backbone”, “skeleton”, or “conductor” (in the musical sense) of the overall solution. It provides the core layout and general structure, plus it increasingly provides server rendering and serves as a conduit for back-end functionality.

User-facing features are typically implemented as “framework components” which are then rendered into islands by an Astro layout or page.

Delivering a smooth UX

Common application features including authentication, alerts and notifications, modals, and others benefit from a level of coordination across the front-end to deliver a smooth and SaaSy modern UX.

High-quality modern apps don’t have hard redirects or page refreshes and they don’t impose real or perceived delays.

Thus it becomes important for Astro layouts, pages, and components that provide a “shell” to be fully in tune with application features in islands and vice versa.

Shared state is also important for coordinating state across islands.

As much as frameworks like React and Vue have context API’s to share state within a component tree but they only work within a given island. In many respects each island is its own app.

Common patterns for implementing global authentication context, theme context, and many more are disrupted when islands break things up.

Zustand to the rescue!

Why zustand vs. alternatives?

Astro’s official docs include a recipe Sharing State Between Islands that recommend nanostores.

The guide doesn’t mention any of the various other dedicated state management libraries in the ecosystem though it does mention a few framework-specific choices as well as using Custom Events.

So why would we want to consider zustand?

Well-known and widely respected

Zustand is hugely popular with over 3.5M weekly npm downloads at the time of writing.

It’s also backed by pmndrs, the open-source developer collective that maintains legendary libraries including react-spring, react-three-fiber, use-gesture, use-cannon and many more.

Its original author @dai-shi is an authority on state management.

In contrast nanostores is orders of magnitudes less popular with ~60K weekly npm downloads and is primarily maintained by a single consultancy.

While EvilMartians are an incredible team that produces brilliant work and they write a great blog that has taught me many things, at the end of the day they are just one shop and for all we know their interest in maintaining the library may be fleetingly tied to a specific project or client.

Customizable and flexible

Zutand is very flexible and is customizable with plugins, various persistence options, and more while staying lightweight and performant.

Its also a great choice vs. various alternatives because how it stores state is not dependent on any framework.

The way it works is aligned with our goals

Here’s an issue answer by @dai-shi, author and maintainer of three popular state management frameworks: zustand, jotai, and voltio; plus maintainer of React Server Components, where he compares jotai vs. zustand and explains their differences.

While his answer and the discussion is a few years old it is still relevant and concludes:
“If you want to update state outside React, zustand works better.”

That’s us!

It loves React

Like many others when it comes to professional work I care most about React and how well things work when Astro + React are combined. It’s #1 in industry and is likely going to stay that way for some time.

Zustand happens to be particularly React friendly; so much so that I’ve seen many posts incorrectly describe it as a “react library”.

While its universal and fully compatible with VanillaJS, compatibility with a React is a top priority as evidenced by numerous discussions and issues on the projects. The maintainers are clearly deeply committed to ensuring continued excellence.

Its also a top-choice for high performance state management when it comes to webGL/3D projects in React that use @react-three/fiber (react-three-fiber).

Give it a Shot