zimmer-context
v0.2.0
Published
Dead simple state management with context using zustand and immer
Downloads
7
Maintainers
Readme
Complex zustand slices patterns made simple with full typescript support
Getting Started
Install the package with
npm install zimmer-context
Using the package
It is dead simple, this library provides only 2 functions:
createStoreSlice
to define your slicescreateGlobalStoreContext
to use your slices and get yourContextProvider
anduseStoreContext
hook to use the store
I felt there was too much boilerplate when using zustand with immer and persist, especially as my projects grew, so I created this package. Everything is fully typed and as simple as possible.
1. Creating slices
Create a file store/fishSlice.ts
, where you define your slice with createStoreSlice
. First define your state and actions. then inside the createStoreSlice define the default values and the functions. you have access to set and get fucnctions to retrieve and manipulate with the data in this slice. You cannot access data in another slices, as at the time of defining your slice, typescript doesn't know aobut the structure of other slices.
import { createStoreSlice } from "zimmer-context";
type FishState = {
count: number;
};
type FishActions = {
increment: (qty: number) => void;
decrement: (qty: number) => void;
};
export const fishSlice = createStoreSlice<FishState, FishActions>(
(set, get) => ({
count: 0,
increment: (qty: number) => set((state) => ({ count: state.count + qty })),
decrement: (qty: number) => set((state) => ({ count: state.count - qty })),
})
);
and another store/bearSlice.ts
slice like so:
import { createStoreSlice } from "zimmer-context";
type BearState = {
count: number;
};
type BearActions = {
increment: (qty: number) => void;
decrement: (qty: number) => void;
};
export const bearSlice = createStoreSlice<BearState, BearActions>(
(set, get) => ({
count: 0,
increment: (qty: number) => set((state) => ({ count: state.count + qty })),
decrement: (qty: number) => set((state) => ({ count: state.count - qty })),
})
);
2. Create your global store using slices
In another file (say store/global_store.ts
) import all of the slices and create the global store:
"use client";
import { createGlobalStoreContext } from "zimmer-context";
import { bearSlice } from "./bear_slice";
import { fishSlice } from "./fish_slice";
export const { ContextProvider, useStoreContext } = createGlobalStoreContext(
{
fish: fishSlice,
bear: bearSlice,
},
{
persist: {
// Do not specify to not use persist
version: 1, // Persist version, change whenever there is a breaking change in the structure of the store
},
}
);
3. Provide the context with ContextProvider
Here you can override the initial store state with your data, such as fetched one, or from URL search parameters.
import { ContextProvider } from "store/global_store";
export default async function ReactComponent({
children,
}: {
children: React.ReactNode;
}) {
return (
<ContextProvider
initStoreState={{
fish: { count: 10 },
}}
>
{children}
</ContextProvider>
);
}
4. Use the store with useStoreContext
Inside the ContextProvider you can get the state like so:
import { useStoreContext } from "store/global_store";
export default async function DisplayCounts() {
const { fish, bear } = useStoreContext((state) => state);
return (
<div>
<div>fish: {fish.count}</div>
<div>bear: {bear.count}</div>
<button
onClick={() => {
fish.decrement(1);
}}
>
Bear eats fish
</button>
</div>
);
}
Contributing
Feel free to open issues and contribute by creating pull requests! I am open to any and all suggestions.