-
-
Save kyle-mccarthy/cae2df1089c71b9d6f5eb55992a15474 to your computer and use it in GitHub Desktop.
import type { GetState, PartialState, SetState, State } from "zustand"; | |
const noop = (..._: unknown[]): void => { | |
/* noop */ | |
}; | |
export type Setter<T extends State> = ( | |
s: Partial<T> | ((prev: T) => Partial<T>), | |
replace?: boolean | |
) => void; | |
export type Factory<T extends State> = (set: Setter<T>, get: () => T) => T; | |
// Zustand recommnds splitting the store into separate "slices", but doesn't | |
// really provide a great way to do this. [^slices] | |
// | |
// This allows for easily creating slices that are encapsulated as an object in | |
// the primary store. `createSlice` does this by re-scoping the get and set | |
// functions to the slice based on the property name passed as the first arg. | |
// | |
// # Example | |
// | |
// ## Create the slice for the primary store | |
// ``` | |
// interface UserSlice { | |
// id?: number; | |
// email?: string; | |
// setId: (id: number) => void; | |
// setEmail: (email: string) => void; | |
// } | |
// | |
// const userFactory: Factory<AddressSlice> = (set, _get) => ({ | |
// setId: (id: number) => set({ id }), | |
// setEmail: (email: string) => set({ email }), | |
// }); | |
// | |
// const createUserSlice = createSlice("user", userFactory); | |
// ``` | |
// | |
// ## Create the store and include your slice | |
// ``` | |
// import { create } from "zustand"; | |
// | |
// interface Store { | |
// user: UserSlice; | |
// ... | |
// } | |
// | |
// const store = create((set, get) => ({ | |
// user: createUserSlice(set, get), | |
// })); | |
// ``` | |
// | |
// [^slices]: https://github.com/pmndrs/zustand/wiki/Splitting-the-store-into-separate-slices | |
export const createSlice = < | |
P extends keyof Z, | |
S extends State, | |
Z extends { [k in P]: S } | |
>( | |
property: P, | |
factory: Factory<S> | |
): ((set: SetState<Z>, get: GetState<Z>) => S) => { | |
return (set, get) => { | |
const getter = (): S => { | |
return get()[property]; | |
}; | |
const setter: Setter<S> = (arg, replace) => { | |
const prev = get()[property]; | |
const next = typeof arg === "function" ? arg(prev) : arg; | |
if (next === prev) { | |
return noop(); | |
} | |
if (replace) { | |
return set({ [property]: next as S } as PartialState<Z>); | |
} | |
return set({ | |
[property]: { | |
...prev, | |
...next, | |
} as S, | |
} as PartialState<Z>); | |
}; | |
return factory(setter, getter); | |
}; | |
}; |
I've tried using this and being new to Zustand I can't get it to work fully, as the 4 imports are all deprecated.
import { GetState, PartialState, SetState, State } from "zustand";
When I use it the 2nd one of the 2 below works, however as soon as I wrap immer, devtools or even persist around it (the first one), I get red squiggle lines. Would it be possible for you to update the above code to use the latest version of Zustand?
export const useStoreFactory = createSelectors(
create(
immer((set, get) => ({
user: createUserSlice(set, get),
userSettings: createUserSettingsSlice(set, get),
}))
)
);
export const useStoreFactoryWorks = createSelectors(
create((set, get) => ({
user: createUserSlice(set, get),
userSettings: createUserSettingsSlice(set, get),
}))
);
Zustand used to treat all state as an object. It looks like that changed recently.