reactjszustand

Zustand and Global Access: What's Wrong Here?


I've done a lot of searching, and have even tried copying examples I've seen around the Internet, but I'm either misunderstanding, missing information, or just plain doing it wrong when trying to use the "global access" promise of Zustand.

Code

I've got my store (/src/Components/Zustand/State/index.tsx):

import create from 'zustand';

// The bucket
type State = {
    count: number
}

// Actions
type Actions = {
    increment: (qty: number) => void,
    decrement: (qty: number) => void
}

// Create the state
const useStore = create<State & Actions>((set)=>({
    count: 0,
    increment: (qty: number) => set((state)=>({count: state.count + 1})),
    decrement: (qty: number) => set((state)=>({count: state.count - 1})),
}))

export default useStore;

And I have two components, Home1 and Home2. Aside from their names and hyperlinks between one another, they are identical (/src/Components/Zustand/Home1/index.tsx and /src/Components/Zustand/Home2/index.tsx):

import useStore from '../State/';

const Home1 = (props) =>{
   
    // I have also tried
    // const count = useStore((state)=>state.count), etc
    const { count, increment, decrement } = useStore();

    return (
        <>
            <div>{count}</div>
            <div><button onClick={increment}>Increase</button></div>
            <div><button onClick={decrement}>Decrease</button></div>
            <div><a href='home2'>Home 2</a></div>
        </>
    )
}

export { Home1 }
import useStore from '../State/';

const Home2 = (props) =>{
    
    const { count, increment, decrement } = useStore();

    return (
        <>
            <div>{count}</div>
            <div><button onClick={increment}>Increase</button></div>
            <div><button onClick={decrement}>Decrease</button></div>
            <div><a href='/'>Home 1</a></div>
        </>
    )
}

export { Home2 }

Using React Router, I've defined my routes from the App.tsx component so I can navigate around:

import {
  createBrowserRouter,
  RouterProvider,
} from "react-router-dom";


import { Home1 } from './Components/Zustand/Home1'
import { Home2 } from './Components/Zustand/Home2'

const router = createBrowserRouter([
  {
    path: '/',
    Component: Home1
  },
  {
    path: '/home2',
    Component: Home2
  }
])

export default function App() {
  return (
      <RouterProvider router={router} />
  )
}

Here's the app at Codesandbox

The Assumption

Using the increment and decrement buttons on Home1 or Home2 should increase or decrease the value of count...which it does within the same component. But I was under the impression that "global" means I can import useState from the state component and get the value of count that was set in Home1 in the other component, Home2.

The Issue

When incrementing count in Home1 I see the update, but switching to Home2 the count is back to 0.

Is my code setup wrong? Or am I under the wrong impression about how Zustand works? The store is updating, but only in the immediate components; the updates are not carrying over between components.

I've looked at countless examples and explanations, and my code looks sound based on everything I've read, but I feel like I'm missing something that puts the "global" into Zustand's claim that it's a global state.


Solution

  • I recommend using React Router's Link component for navigating between pages because Link handles navigation internally within your single-page application (SPA), providing a smoother user experience. In contrast, using the a element directly triggers a full page refresh, disrupting the flow of your application.

    import useStore from "../State/";
    import { Link } from "react-router-dom";
    
    const Home2 = (props) => {
      const { count, increment, decrement } = useStore();
    
      return (
        <>
          <div>{count}</div>
          <div>
            <button onClick={increment}>Increase</button>
          </div>
          <div>
            <button onClick={decrement}>Decrease</button>
          </div>
          <div>
            <Link to="/">Home 1</Link>
          </div>
        </>
      );
    };
    
    export { Home2 };