Skip to content

Enjoy the performance gain of selectors without writing selectors in Zustand.

License

Notifications You must be signed in to change notification settings

Albert-Gao/auto-zustand-selectors-hook

Repository files navigation

auto-zustand-selectors-hook

Enjoy the performance gain of selectors without writing selectors!

Features

  • auto generate selectors for Zustand store (be it a value or a function)
  • Two styles available
  • Fully Typescript support (auto-completion for the generated selectors!)

Install

npm install --save auto-zustand-selectors-hook

Or with yarn:

yarn add auto-zustand-selectors-hook

Notice

The v2 supports Zustand v4, if you are using a Zustand v3, please install the v1 version

yarn add [email protected]

npm install --save [email protected]

Usage

Let's say you have a store like this

interface BearState {
  bears: number;
  increase: (by: number) => void;
}

const useStoreBase = create<BearState>((set) => ({
  bears: 0,
  increase: (by) => set((state) => ({ bears: state.bears + by })),
}));

There are two types of selectors you can generate, purely function signature difference, underneath, they are all selectors.

1. For function style ( createSelectorFunctions )

import { createSelectorFunctions } from 'auto-zustand-selectors-hook';
import { create } from 'zustand';

// wrap your store
const useStore = createSelectorFunctions(useStoreBase);

// use it like this!
// useStore.use.blah is a pre-generated selector, yeah!
const TestComponent = () => {
  const bears = useStore.use.bears();
  const increase = useStore.use.increase();

  return (
    <>
      <span>{bears}</span>

      <button
        onClick={() => {
          increase(1);
        }}
      >
        +
      </button>
    </>
  );
};

2. For hook style ( createSelectorHooks )

import { createSelectorHooks } from 'auto-zustand-selectors-hook';
import { create } from 'zustand';

// wrap your store
const useStore = createSelectorHooks(useStoreBase);

// use it like this!
// useStore.useBlah is a pre-generated selector, yeah!
const TestComponent = () => {
  const bears = useStore.useBears();
  const increase = useStore.useIncrease();

  return (
    <>
      <span>{bears}</span>

      <button
        onClick={() => {
          increase(1);
        }}
      >
        +
      </button>
    </>
  );
};

3. use with middlewares

You use the middleware for creating the base store, and ALWAYS use auto-zustand-selectors-hooks as a separate wrapper

import {
  createSelectorHooks,
  ZustandFuncSelectors,
  ZustandHookSelectors,
} from 'auto-zustand-selectors-hook';
import create from 'zustand';
import { persist } from 'zustand/middleware';

const useStoreBase = create<BearState>()(
  persist((set) => ({
    bears: 0,
    increase: (by) => set((state) => ({ bears: state.bears + by })),
  }))
);

// ❌ this will lost  the persist middleware type like useStore.persist
export const useStore = createSelectorHooks(useStoreBase);

// ✅ DO this if use createSelectorFunctions()
export const useStore = createSelectorFunctions(
  useStoreBase
) as typeof useStoreBase & ZustandFuncSelectors<BearState>;

// ✅ DO this if use createSelectorHooks()
export const useStore = createSelectorHooks(
  useStoreBase
) as typeof useStoreBase & ZustandHookSelectors<BearState>;

License

MIT © Albert Gao

Credits

It all starts from my feature request Thanks dai-shi for the initial implementation and ideas of API.