This commit is contained in:
pincman 2024-05-14 19:13:18 +08:00
parent 18d79b79a7
commit 112b737cc4
5 changed files with 207 additions and 1 deletions

View File

@ -22,7 +22,8 @@
"immer": "^10.1.1",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"zustand": "^4.5.2"
},
"devDependencies": {
"@3rapp/code-config": "workspace:*",

View File

@ -0,0 +1,2 @@
export * from './utils';
export * from './types';

View File

@ -0,0 +1,8 @@
export type ZustandHookSelectors<StateType> = {
[Key in keyof StateType as `use${Capitalize<string & Key>}`]: () => StateType[Key];
};
export interface ZustandGetterSelectors<StateType> {
getters: {
[key in keyof StateType]: () => StateType[key];
};
}

View File

@ -0,0 +1,160 @@
import { capitalize } from 'lodash';
import { create, Mutate, StateCreator, StoreApi, UseBoundStore } from 'zustand';
import {
subscribeWithSelector,
devtools,
persist,
PersistOptions,
DevtoolsOptions,
redux,
} from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { ZustandGetterSelectors, ZustandHookSelectors } from './types';
/**
* immer以及devtoools功能的普通状态商店
* @param creator
* @param devtoolsOptions
*/
export const createStore = <T extends object>(
creator: StateCreator<
T,
[
['zustand/subscribeWithSelector', never],
['zustand/immer', never],
['zustand/devtools', never],
]
>,
devtoolsOptions?: DevtoolsOptions,
) => {
return create<T>()(subscribeWithSelector(immer(devtools(creator, devtoolsOptions))));
};
/**
* immer以及devtoools功能的普通状态商店
* localstorage
* @param creator
* @param persistOptions
* @param devtoolsOptions
*/
export const createPersistStore = <T extends object, P = T>(
creator: StateCreator<
T,
[
['zustand/subscribeWithSelector', never],
['zustand/immer', never],
['zustand/devtools', never],
['zustand/persist', P],
]
>,
persistOptions: PersistOptions<T, P>,
devtoolsOptions?: DevtoolsOptions,
) => {
return create<T>()(
subscribeWithSelector(
immer(devtools(persist(creator as unknown as any, persistOptions), devtoolsOptions)),
),
);
};
/**
* immer以及devtoools功能的reducer状态商店
* localstorage
* @param reducer
* @param initialState
* @param devtoolsOptions
*/
export const createReduxStore = <
T extends object,
A extends {
type: string;
},
>(
reducer: (state: T, action: A) => T,
initialState: T,
devtoolsOptions?: DevtoolsOptions,
) => create(subscribeWithSelector(immer(devtools(redux(reducer, initialState), devtoolsOptions))));
/**
* immer以及devtoools功能的reducer状态商店
* @param reducer
* @param initialState
* @param persistOptions
* @param devtoolsOptions
*/
export const createPersistReduxStore = <
T extends object,
A extends {
type: string;
},
P = T,
>(
reducer: (state: T, action: A) => T,
initialState: T,
persistOptions: PersistOptions<T, P>,
devtoolsOptions?: DevtoolsOptions,
) =>
create(
subscribeWithSelector(
immer(
devtools(
persist(redux(reducer, initialState), persistOptions as any),
devtoolsOptions,
),
),
),
);
/**
* getters获取状态值store.getters.xxx()
* @param store
*/
export function createStoreGetters<T extends object>(
store: UseBoundStore<
Mutate<
StoreApi<T>,
[
['zustand/subscribeWithSelector', never],
['zustand/immer', never],
['zustand/devtools', never],
]
>
>,
) {
const storeIn = store as any;
storeIn.getters = {};
Object.keys(storeIn.getState()).forEach((key) => {
const selector = (state: T) => state[key as keyof T];
storeIn.getters[key] = () => storeIn(selector);
});
return storeIn as typeof store & ZustandGetterSelectors<T>;
}
/**
* hooks的方法获取状态值store.useXxx()
* @param store
*/
export function createStoreHooks<T extends Record<string, any>>(
store: UseBoundStore<
Mutate<
StoreApi<T>,
[
['zustand/subscribeWithSelector', never],
['zustand/immer', never],
['zustand/devtools', never],
]
>
>,
) {
const storeIn = store as any;
Object.keys(storeIn.getState()).forEach((key) => {
const selector = (state: T) => state[key as keyof T];
storeIn[`use${capitalize(key)}`] = () => storeIn(selector);
});
return storeIn as typeof store & ZustandHookSelectors<T>;
}

View File

@ -56,6 +56,9 @@ importers:
react-dom:
specifier: ^18.2.0
version: 18.3.1(react@18.3.1)
zustand:
specifier: ^4.5.2
version: 4.5.2(@types/react@18.3.1)(immer@10.1.1)(react@18.3.1)
devDependencies:
'@3rapp/code-config':
specifier: workspace:*
@ -5432,6 +5435,11 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
use-sync-external-store@1.2.0:
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -5606,6 +5614,21 @@ packages:
engines: {node: '>=8.0.0'}
hasBin: true
zustand@4.5.2:
resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==}
engines: {node: '>=12.7.0'}
peerDependencies:
'@types/react': '>=16.8'
immer: '>=9.0.6'
react: '>=16.8'
peerDependenciesMeta:
'@types/react':
optional: true
immer:
optional: true
react:
optional: true
snapshots:
'@alloc/quick-lru@5.2.0': {}
@ -11360,6 +11383,10 @@ snapshots:
dependencies:
punycode: 2.3.1
use-sync-external-store@1.2.0(react@18.3.1):
dependencies:
react: 18.3.1
util-deprecate@1.0.2: {}
uuid@9.0.1: {}
@ -11553,3 +11580,11 @@ snapshots:
validator: 13.12.0
optionalDependencies:
commander: 9.5.0
zustand@4.5.2(@types/react@18.3.1)(immer@10.1.1)(react@18.3.1):
dependencies:
use-sync-external-store: 1.2.0(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.1
immer: 10.1.1
react: 18.3.1