Zustand - create vs createStore

Photo by Andy Holmes on Unsplash

Zustand - create vs createStore

ยท

4 min read

Introduction

We'll explore two core features of Zustand: create and createStore. Confused about when to use which? You're not alone. Let's break down these two functions, compare them, and shed some light on when and why you'd want to use one over the other.

React Rules of Hooks

Before we delve into create and createStore, it's vital to understand a fundamental React principle: the rules of hooks. Hooks are functions that let you tap into React features in functional components. But, there are rules. Breaking them can result in errors or unexpected behavior.

  • Don't Call Hooks Inside Loops, Conditions, or Nested Functions: React relies on the order in which Hooks are called. Doing so in these scenarios can mess that up.

  • Only Call Hooks from React Functions: Whether it's functional components or custom hooks, keep hooks within the React realm.

Understanding create

create is Zustand's way of helping you quickly define a store with state and actions. Think of it as packaging your store neatly into a custom hook that you can call from any component. It's like having your own personal mini-store right in the component. No need for context providers!

Here's how it's done:

import { create } from 'zustand';

interface CounterState {
    counter: number;
    increase: (by: number) => void;
}

const useStore = create<CounterState>()((set) => ({
    counter: 0,
    increase: (by) => set((state) => ({ counter: state.counter + by })),
}));

export default function Counter() {
    // const { counter, increase } = useStore();
    // or
    const counter = useStore((state) => state.counter);
    const increase = useStore((state) => state.increase);

    const handleClick = () => {
        increase(1);
    };
    return (
        <div>
            <span>{counter}</span>
            <button onClick={handleClick}>one up</button>
        </div>
    );
}
  • Pros:

    • Simplicity: No context providers needed.

    • Flexibility: Easily create and use local state.

  • Cons:

    • Possible Violation of Hook Rules: When passed through contexts, you may violate React's rules of hooks. Thus, it is not recommended to do the following:

        const CounterContext = createContext<typeof useStore | null>(null);
      

Understanding createStore

Now, createStore takes a slightly different approach. Instead of returning a custom hook, it returns the store object itself. Ideal for when you want to pass your store around through contexts or props.

import { createContext, useContext, useRef } from 'react';
import { createStore, useStore } from 'zustand';

interface CounterState {
    counter: number;
    increase: (by: number) => void;
}

const useCreateStore = createStore<CounterState>()((set) => ({
    counter: 0,
    increase: (by) => set((state) => ({ counter: state.counter + by })),
}));

const CounterContext = createContext<typeof useCreateStore | null>(null);

function CounterContextProvider({ children }: { children: React.ReactNode }) {
    const store = useRef(useCreateStore);

    return (
        <CounterContext.Provider value={store.current}>
            {children}
        </CounterContext.Provider>
    );
}

function Counter() {
    const store = useContext(CounterContext);
    if (!store) throw new Error('Missing CounterContext.Provider in the tree');
    const counter = useStore(store, (state) => state.counter);
    const increase = useStore(store, (state) => state.increase);

    const handleClick = () => {
        increase(1);
    };
    return (
        <div>
            <span>{counter}</span>
            <button onClick={handleClick}>one up</button>
        </div>
    );
}

export default function App() {
    return (
        <CounterContextProvider>
            <Counter />
        </CounterContextProvider>
    );
}
  • Pros:

    • Context-Friendly: Great for sharing the store across components.

    • Avoids Violation of Hook Rules: By passing the store object instead of a hook.

  • Cons:

    • Slightly More Complex: Requires context setup.

Comparative Analysis

So, create or createStore?

  • Use create: When dealing with local state within components.

  • Use createStore: When sharing the store across different parts of the app through context or props.

FunctionReturnsIdeal For
createCustom HookLocal state, Simplicity
createStoreStore ObjectContext sharing, Avoid violating hook rule

Conclusion

When choosing either create or createStore, consider your use case and your specific needs. Experiment, explore, and don't be afraid to create another app to mess around and learn before implementing the functionality in your main project. Zustand is here to make your state management journey easier, and understanding these functions is your first step.

I hope you've found this guide helpful - feel free to follow me on Twitter! ๐Ÿš€

References

ย