@chhsiao1981/use-thunk 11.0.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -99
- package/package.json +10 -16
- package/src/action/ActionOrThunk.ts +1 -1
- package/src/action/index.ts +3 -3
- package/src/action/thunk.ts +10 -2
- package/src/defaultThunks/index.ts +15 -0
- package/src/defaultThunks/init/index.ts +27 -0
- package/src/{init → defaultThunks/init}/initCore.ts +2 -2
- package/src/{remove.ts → defaultThunks/remove.ts} +2 -2
- package/src/{setDefaultID.ts → defaultThunks/setDefaultID.ts} +4 -3
- package/src/{update.ts → defaultThunks/update.ts} +2 -7
- package/src/defaultThunks/upsert.ts +27 -0
- package/src/dispatch.ts +7 -0
- package/src/get.ts +4 -0
- package/src/index.ts +43 -31
- package/src/reducer/createReducer.ts +18 -0
- package/src/reducer/defaultReduceMap.ts +26 -0
- package/src/{reducer.ts → reducer/index.ts} +5 -2
- package/src/reducer/reduceMap.ts +6 -0
- package/src/{createThunk.ts → registerThunk.ts} +11 -13
- package/src/set/index.ts +9 -0
- package/src/{setMap.ts → set/setMap.ts} +12 -18
- package/src/states/index.ts +84 -0
- package/src/{stateTypes.ts → states/types.ts} +7 -7
- package/src/thunkContext/index.ts +9 -0
- package/src/{thunkContextMap.ts → thunkContext/thunkContextMap.ts} +2 -2
- package/src/{thunkContextTypes.ts → thunkContext/types.ts} +1 -1
- package/src/thunkModule/defaultDoModule.ts +13 -0
- package/src/thunkModule/index.ts +12 -12
- package/src/{useThunk.ts → useThunk/index.ts} +7 -10
- package/src/{useThunkReducer.ts → useThunk/useThunkReducer.ts} +50 -10
- package/src/utils/deepCopy.ts +30 -0
- package/src/utils/genID.ts +6 -0
- package/src/utils/index.ts +3 -0
- package/types/action/ActionOrThunk.d.ts +1 -1
- package/types/action/index.d.ts +2 -2
- package/types/action/thunk.d.ts +4 -2
- package/types/defaultThunks/index.d.ts +10 -0
- package/types/defaultThunks/init/index.d.ts +9 -0
- package/types/{init → defaultThunks/init}/initCore.d.ts +2 -2
- package/types/{remove.d.ts → defaultThunks/remove.d.ts} +2 -2
- package/types/{setDefaultID.d.ts → defaultThunks/setDefaultID.d.ts} +2 -2
- package/types/{update.d.ts → defaultThunks/update.d.ts} +2 -3
- package/types/defaultThunks/upsert.d.ts +5 -0
- package/types/dispatch.d.ts +4 -4
- package/types/get.d.ts +3 -0
- package/types/index.d.ts +11 -20
- package/types/reducer/createReducer.d.ts +3 -0
- package/types/reducer/defaultReduceMap.d.ts +2 -0
- package/types/{reducer.d.ts → reducer/index.d.ts} +4 -2
- package/types/reducer/reduceMap.d.ts +5 -0
- package/types/{createThunk.d.ts → registerThunk.d.ts} +1 -2
- package/types/set/index.d.ts +5 -0
- package/types/set/setMap.d.ts +16 -0
- package/types/states/index.d.ts +10 -0
- package/types/{stateTypes.d.ts → states/types.d.ts} +6 -6
- package/types/thunkContext/index.d.ts +6 -0
- package/types/{thunkContextMap.d.ts → thunkContext/thunkContextMap.d.ts} +2 -2
- package/types/{thunkContextTypes.d.ts → thunkContext/types.d.ts} +1 -1
- package/types/thunkModule/defaultDoModule.d.ts +5 -0
- package/types/thunkModule/index.d.ts +8 -11
- package/types/useThunk/index.d.ts +9 -0
- package/types/{useThunkReducer.d.ts → useThunk/useThunkReducer.d.ts} +3 -3
- package/types/utils/deepCopy.d.ts +2 -0
- package/types/utils/genID.d.ts +1 -0
- package/types/utils/index.d.ts +3 -0
- package/src/createReducer.ts +0 -24
- package/src/genUUID.ts +0 -38
- package/src/init/index.ts +0 -26
- package/src/reduceMap.ts +0 -22
- package/src/set.ts +0 -7
- package/src/states.ts +0 -47
- package/src/thunkModule/defaultThunkModuleFuncMap.ts +0 -16
- package/types/createReducer.d.ts +0 -4
- package/types/dispatchFuncMap.d.ts +0 -17
- package/types/genUUID.d.ts +0 -1
- package/types/init/index.d.ts +0 -7
- package/types/reduceMap.d.ts +0 -6
- package/types/set.d.ts +0 -4
- package/types/setMap.d.ts +0 -17
- package/types/states.d.ts +0 -9
- package/types/thunkModule/defaultThunkModuleFuncMap.d.ts +0 -5
- package/types/useThunk.d.ts +0 -9
- /package/src/{ThunkContext.tsx → thunkContext/ThunkContext.tsx} +0 -0
- /package/types/{ThunkContext.d.ts → thunkContext/ThunkContext.d.ts} +0 -0
package/src/index.ts
CHANGED
|
@@ -1,46 +1,58 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import type { set } from './set'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import type { getModuleState, Thunk, ThunkFunc } from './action'
|
|
2
|
+
import { type InitParams, init, remove, setDefaultID, update, upsert } from './defaultThunks'
|
|
3
|
+
import type { dispatch } from './dispatch'
|
|
4
|
+
import type { get, getOrNull } from './get'
|
|
5
|
+
import registerThunk from './registerThunk'
|
|
6
|
+
import type { set, setMap } from './set'
|
|
7
|
+
import {
|
|
8
|
+
getDefaultID,
|
|
9
|
+
getNodeOrNull,
|
|
10
|
+
getState,
|
|
11
|
+
getStateByModule,
|
|
12
|
+
getStateOrNullByModule,
|
|
13
|
+
type ModuleState,
|
|
14
|
+
type State,
|
|
15
|
+
} from './states'
|
|
16
|
+
import { ThunkContext } from './thunkContext'
|
|
17
|
+
import type { doModule, ThunkModule, toDoModule } from './thunkModule'
|
|
14
18
|
import useThunk, { type UseThunk } from './useThunk'
|
|
19
|
+
import { genID } from './utils'
|
|
15
20
|
|
|
16
21
|
export {
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
// thunk definition.
|
|
23
|
+
type Thunk,
|
|
24
|
+
type set,
|
|
25
|
+
type get,
|
|
26
|
+
type getOrNull,
|
|
27
|
+
type dispatch,
|
|
28
|
+
type getModuleState,
|
|
29
|
+
// registerThunk / useThunk / ThunkContext
|
|
30
|
+
registerThunk,
|
|
19
31
|
useThunk,
|
|
20
32
|
type UseThunk,
|
|
21
33
|
ThunkContext,
|
|
34
|
+
// state related.
|
|
22
35
|
type State,
|
|
36
|
+
getState,
|
|
23
37
|
type ModuleState,
|
|
24
|
-
|
|
25
|
-
type GetModuleState,
|
|
26
|
-
type GetModuleState as GetClassState, // to deprecate
|
|
27
|
-
type Thunk,
|
|
38
|
+
// module related.
|
|
28
39
|
type ThunkModule,
|
|
29
|
-
type
|
|
30
|
-
type
|
|
31
|
-
type
|
|
32
|
-
|
|
33
|
-
type setMap,
|
|
34
|
-
getNode,
|
|
35
|
-
getDefaultID,
|
|
36
|
-
getState,
|
|
37
|
-
mustGetState,
|
|
38
|
-
mustGetStateByThunk,
|
|
40
|
+
type toDoModule,
|
|
41
|
+
type doModule,
|
|
42
|
+
type ThunkFunc,
|
|
43
|
+
// default thunks.
|
|
39
44
|
init,
|
|
40
45
|
type InitParams,
|
|
41
|
-
setData, // to deprecate
|
|
42
46
|
update,
|
|
47
|
+
upsert,
|
|
43
48
|
remove,
|
|
49
|
+
// genID
|
|
50
|
+
genID,
|
|
51
|
+
// advanced usage.
|
|
52
|
+
type setMap,
|
|
44
53
|
setDefaultID,
|
|
45
|
-
|
|
54
|
+
getNodeOrNull,
|
|
55
|
+
getDefaultID,
|
|
56
|
+
getStateOrNullByModule,
|
|
57
|
+
getStateByModule,
|
|
46
58
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BaseAction } from '../action'
|
|
2
|
+
import type { ModuleState, State } from '../states'
|
|
3
|
+
import { DEFAULT_REDUCE_MAP } from './defaultReduceMap'
|
|
4
|
+
import type { Reducer } from './index'
|
|
5
|
+
|
|
6
|
+
export const createReducer = <S extends State>(): Reducer<S> => {
|
|
7
|
+
return (moduleState: ModuleState<S>, action: BaseAction): ModuleState<S> => {
|
|
8
|
+
if (!action) {
|
|
9
|
+
return moduleState
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (DEFAULT_REDUCE_MAP[action.type]) {
|
|
13
|
+
return DEFAULT_REDUCE_MAP[action.type](moduleState, action)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return moduleState
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INIT,
|
|
3
|
+
REMOVE,
|
|
4
|
+
reduceInit,
|
|
5
|
+
reduceRemove,
|
|
6
|
+
reduceSetDefaultID,
|
|
7
|
+
reduceUpdate,
|
|
8
|
+
reduceUpsert,
|
|
9
|
+
SET_DEFAULT_ID,
|
|
10
|
+
UPDATE,
|
|
11
|
+
UPSERT,
|
|
12
|
+
} from '../defaultThunks'
|
|
13
|
+
import type { ReduceMap } from './reduceMap'
|
|
14
|
+
|
|
15
|
+
// biome-ignore lint/suspicious/noExplicitAny: DEFAULT_REDUCE_MAP can apply to any States.
|
|
16
|
+
export const DEFAULT_REDUCE_MAP: ReduceMap<any> = {
|
|
17
|
+
[INIT]: reduceInit,
|
|
18
|
+
[UPDATE]: reduceUpdate,
|
|
19
|
+
[REMOVE]: reduceRemove,
|
|
20
|
+
[UPSERT]: reduceUpsert,
|
|
21
|
+
|
|
22
|
+
// setDefaultID.
|
|
23
|
+
// Typically we don't need this in programming.
|
|
24
|
+
// The defaultID is automatically determined if defaultID is not set.
|
|
25
|
+
[SET_DEFAULT_ID]: reduceSetDefaultID,
|
|
26
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Reducer as rReducer } from 'react'
|
|
2
|
-
import type BaseAction from '
|
|
3
|
-
import type { ModuleState, State } from '
|
|
2
|
+
import type { BaseAction } from '../action'
|
|
3
|
+
import type { ModuleState, State } from '../states'
|
|
4
|
+
|
|
5
|
+
import { createReducer } from './createReducer'
|
|
6
|
+
export { createReducer }
|
|
4
7
|
|
|
5
8
|
// Reducer
|
|
6
9
|
export type Reducer<S extends State> = rReducer<ModuleState<S>, BaseAction>
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
// Reason for registerThunk instead of createThunk:
|
|
2
|
+
// I feel that createThunk needs to return some object
|
|
3
|
+
// as the proof of successful creation.
|
|
4
|
+
// However, we register Thunks to the global state management
|
|
5
|
+
// system and return void.
|
|
1
6
|
import { createContext, type Dispatch, type SetStateAction } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { THUNK_CONTEXT_MAP } from './thunkContextMap'
|
|
7
|
+
import type { ModuleState, State } from './states'
|
|
8
|
+
import { THUNK_CONTEXT_MAP } from './thunkContext'
|
|
5
9
|
import type { ThunkModule } from './thunkModule'
|
|
6
10
|
|
|
7
11
|
export default <S extends State>(theDo: ThunkModule<S>) => {
|
|
8
|
-
const { name
|
|
9
|
-
const name = (propsName ? propsName : myClass) || ''
|
|
12
|
+
const { name, defaultState } = theDo
|
|
10
13
|
|
|
11
14
|
if (THUNK_CONTEXT_MAP.theMap[name]) {
|
|
12
|
-
console.warn('
|
|
15
|
+
console.warn('registerThunk: already init:', name)
|
|
13
16
|
return
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
const moduleState: ModuleState<S> = {
|
|
19
|
+
const moduleState: ModuleState<S> = { name, nodes: {}, defaultState }
|
|
17
20
|
const setModuleState: Dispatch<SetStateAction<ModuleState<S>>> = () => {}
|
|
18
21
|
const refModuleState = { current: moduleState }
|
|
19
22
|
const context = createContext({ refModuleState: refModuleState, setModuleState })
|
|
@@ -22,10 +25,5 @@ export default <S extends State>(theDo: ThunkModule<S>) => {
|
|
|
22
25
|
const theList = Object.keys(THUNK_CONTEXT_MAP.theMap).sort()
|
|
23
26
|
THUNK_CONTEXT_MAP.theList = theList
|
|
24
27
|
|
|
25
|
-
console.info('
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const registerThunk = <S extends State>(theDo: ThunkModule<S>) => {
|
|
29
|
-
console.warn('registerThunk will be deprecated in the next version.')
|
|
30
|
-
return createThunk(theDo)
|
|
28
|
+
console.info('registerThunk: done:', name)
|
|
31
29
|
}
|
package/src/set/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// XXX requiring to import directly from action/ActionOrThunk, or it will cause looping.
|
|
2
|
+
import type { ActionOrThunk } from '../action'
|
|
3
|
+
import type { State } from '../states'
|
|
4
|
+
|
|
5
|
+
import { constructSetMap, type DefaultSetMap, type setMap, type setMapByModuleMap } from './setMap'
|
|
6
|
+
export { constructSetMap, type DefaultSetMap, type setMap, type setMapByModuleMap }
|
|
7
|
+
|
|
8
|
+
// set
|
|
9
|
+
export type set<S extends State> = (actionOrID: ActionOrThunk<S> | string, data?: Partial<S>) => void
|
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
import type { ActionFunc } from '
|
|
2
|
-
import type { set } from '
|
|
3
|
-
import type { State } from '
|
|
4
|
-
import type {
|
|
5
|
-
import {
|
|
6
|
-
DEFAULT_THUNK_MODULE_FUNC_MAP,
|
|
7
|
-
type DefaultThunkModuleFuncMap,
|
|
8
|
-
} from './thunkModule/defaultThunkModuleFuncMap'
|
|
1
|
+
import type { ActionFunc } from '../action'
|
|
2
|
+
import type { set } from '../set'
|
|
3
|
+
import type { State } from '../states'
|
|
4
|
+
import type { doModule, ThunkModule } from '../thunkModule'
|
|
5
|
+
import { DEFAULT_DO_MODULE, type defaultDoModule } from '../thunkModule'
|
|
9
6
|
|
|
10
7
|
// biome-ignore lint/suspicious/noExplicitAny: unknown requires same type in list, use any for possible different types.
|
|
11
8
|
type VoidReturnType<T extends (...params: any[]) => unknown> = (...params: Parameters<T>) => void
|
|
12
9
|
|
|
13
|
-
export type setMap<S extends State, T extends
|
|
10
|
+
export type setMap<S extends State, T extends doModule<S>> = {
|
|
14
11
|
[action in keyof T]: VoidReturnType<T[action]>
|
|
15
12
|
} & Omit<DefaultSetMap, keyof T>
|
|
16
13
|
|
|
17
14
|
export type DefaultSetMap = {
|
|
18
|
-
[action in keyof
|
|
15
|
+
[action in keyof defaultDoModule]: VoidReturnType<defaultDoModule[action]>
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
export interface setMapByModuleMap<S extends State, T extends
|
|
22
|
-
[
|
|
18
|
+
export interface setMapByModuleMap<S extends State, T extends doModule<S>> {
|
|
19
|
+
[moduleMap: string]: setMap<S, T>
|
|
23
20
|
}
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
export const SET_MAP_BY_MODULE_MAP: setMapByModuleMap<any, any> = {}
|
|
27
|
-
|
|
28
|
-
export const constructSetMap = <S extends State, T extends ThunkModuleFunc<S>>(
|
|
22
|
+
export const constructSetMap = <S extends State, T extends doModule<S>>(
|
|
29
23
|
theDo: ThunkModule<S>,
|
|
30
24
|
set: set<S>,
|
|
31
25
|
setMap: setMap<S, T>,
|
|
@@ -48,12 +42,12 @@ export const constructSetMap = <S extends State, T extends ThunkModuleFunc<S>>(
|
|
|
48
42
|
return val
|
|
49
43
|
}, setMap)
|
|
50
44
|
|
|
51
|
-
Object.keys(
|
|
45
|
+
Object.keys(DEFAULT_DO_MODULE).reduce((val, eachAction) => {
|
|
52
46
|
if (val[eachAction]) {
|
|
53
47
|
return val
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
const action =
|
|
50
|
+
const action = DEFAULT_DO_MODULE[eachAction]
|
|
57
51
|
|
|
58
52
|
// @ts-expect-error eachAction is in setMap<S, R>
|
|
59
53
|
// biome-ignore lint/suspicious/noExplicitAny: action parameters can be any types.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { setMap } from '../set'
|
|
2
|
+
import type { doModule } from '../thunkModule'
|
|
3
|
+
import type { UseThunk } from '../useThunk'
|
|
4
|
+
import { deepCopy } from '../utils'
|
|
5
|
+
import type { ModuleState, NodeState, NodeStateMap, State } from './types'
|
|
6
|
+
|
|
7
|
+
export type { ModuleState, NodeState, State, NodeStateMap }
|
|
8
|
+
|
|
9
|
+
export const getDefaultID = <S extends State>(moduleState: ModuleState<S>): string => {
|
|
10
|
+
return moduleState.defaultID ?? ''
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const getNodeOrNull = <S extends State>(
|
|
14
|
+
moduleState: ModuleState<S>,
|
|
15
|
+
myID?: string,
|
|
16
|
+
): Readonly<NodeState<S> | null> => {
|
|
17
|
+
const theID = myID ? myID : getDefaultID(moduleState)
|
|
18
|
+
if (!theID) {
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return moduleState.nodes[theID] || null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const getStateOrNullByModule = <S extends State>(
|
|
26
|
+
moduleState: ModuleState<S>,
|
|
27
|
+
myID?: string,
|
|
28
|
+
): Readonly<S | null> => {
|
|
29
|
+
const theID = myID ? myID : getDefaultID(moduleState)
|
|
30
|
+
if (!theID) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const me = moduleState.nodes[theID]
|
|
35
|
+
if (!me) {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return me.state
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const getStateByModule = <S extends State>(
|
|
43
|
+
moduleState: ModuleState<S>,
|
|
44
|
+
myID?: string,
|
|
45
|
+
): Readonly<S> => {
|
|
46
|
+
const theID = myID ? myID : getDefaultID(moduleState)
|
|
47
|
+
if (!theID) {
|
|
48
|
+
return moduleState.defaultState
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const state = getStateOrNullByModule(moduleState, theID)
|
|
52
|
+
if (state) {
|
|
53
|
+
return state
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// XXX magic for new nodes
|
|
57
|
+
// 1. reduceInit
|
|
58
|
+
const newState = deepCopy(moduleState.defaultState)
|
|
59
|
+
const newNode = { id: theID, state: newState }
|
|
60
|
+
moduleState.nodes[theID] = newNode
|
|
61
|
+
|
|
62
|
+
// 2. already init default-id, no need to init default-id here.
|
|
63
|
+
if (moduleState.isInitDefaultID) {
|
|
64
|
+
return newState
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 3. check defaultID
|
|
68
|
+
if (!moduleState.defaultID) {
|
|
69
|
+
moduleState.defaultID = theID
|
|
70
|
+
moduleState.isInitDefaultID = true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return newState
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const getState = <S extends State, R extends doModule<S>>(
|
|
77
|
+
theUseThunk: UseThunk<S, R>,
|
|
78
|
+
myID?: string,
|
|
79
|
+
): [Readonly<S>, setMap<S, R>, string] => {
|
|
80
|
+
const [moduleState, theDo] = theUseThunk
|
|
81
|
+
const theID = myID ? myID : getDefaultID(moduleState)
|
|
82
|
+
const state = getStateByModule(moduleState, theID)
|
|
83
|
+
return [state, theDo, theID]
|
|
84
|
+
}
|
|
@@ -9,15 +9,15 @@ export type NodeState<S extends State> = {
|
|
|
9
9
|
state: S
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export type NodeStateMap<S extends State> = {
|
|
13
|
-
[key: string]: NodeState<S>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
// ModuleState
|
|
17
13
|
export type ModuleState<S extends State> = {
|
|
18
|
-
name
|
|
19
|
-
myClass?: string // XXX to deprecated
|
|
20
|
-
defaultID?: string | null
|
|
14
|
+
name: string
|
|
21
15
|
nodes: NodeStateMap<S>
|
|
22
16
|
defaultState: S
|
|
17
|
+
defaultID?: string | null
|
|
18
|
+
isInitDefaultID?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type NodeStateMap<S extends State> = {
|
|
22
|
+
[key: string]: NodeState<S>
|
|
23
23
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Context } from './types'
|
|
2
|
+
export type { Context }
|
|
3
|
+
|
|
4
|
+
// THUNK_CONTEXT_MAP is used in registerThunk and useThunkReducer
|
|
5
|
+
import { THUNK_CONTEXT_MAP, type ThunkContextMap } from './thunkContextMap'
|
|
6
|
+
export { THUNK_CONTEXT_MAP, type ThunkContextMap }
|
|
7
|
+
|
|
8
|
+
import ThunkContext from './ThunkContext'
|
|
9
|
+
export { ThunkContext }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context as rContext } from 'react'
|
|
2
|
-
import type { ModuleState } from '
|
|
3
|
-
import type { Context } from './
|
|
2
|
+
import type { ModuleState } from '../states'
|
|
3
|
+
import type { Context } from './types'
|
|
4
4
|
|
|
5
5
|
export type ThunkContextMap = {
|
|
6
6
|
theMap: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Dispatch, SetStateAction } from 'react'
|
|
2
|
-
import type { ModuleState, State } from '
|
|
2
|
+
import type { ModuleState, State } from '../states'
|
|
3
3
|
|
|
4
4
|
export type Context<S extends State> = {
|
|
5
5
|
// INFO: we use refModuleState to reference across all the useThunk of the same module in different ops.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ActionFunc } from '../action'
|
|
2
|
+
import { init, remove, update } from '../defaultThunks'
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_DO_MODULE: defaultDoModule = {
|
|
5
|
+
init,
|
|
6
|
+
update,
|
|
7
|
+
remove,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type defaultDoModule = {
|
|
11
|
+
// biome-ignore lint/suspicious/noExplicitAny: defaultDoModule can be any type.
|
|
12
|
+
[action: string]: ActionFunc<any>
|
|
13
|
+
}
|
package/src/thunkModule/index.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import type { ThunkFunc } from '../action'
|
|
2
|
-
import type {
|
|
3
|
-
import type
|
|
2
|
+
import type { State } from '../states'
|
|
3
|
+
import { DEFAULT_DO_MODULE, type defaultDoModule } from './defaultDoModule'
|
|
4
|
+
export { DEFAULT_DO_MODULE, type defaultDoModule }
|
|
4
5
|
|
|
5
|
-
export interface
|
|
6
|
-
[idx: string]: ThunkFunc<S> | string | Reducer<S> | S | undefined
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface ThunkModuleFunc<S extends State> extends ThunkModuleBase<S> {
|
|
6
|
+
export interface doModule<S extends State> {
|
|
10
7
|
[action: string]: ThunkFunc<S>
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
// This is used as the parameter for useThunk.
|
|
14
11
|
export type ThunkModule<S extends State> = {
|
|
15
|
-
name
|
|
16
|
-
myClass?: string // XXX to deprecate
|
|
17
|
-
default?: Reducer<S>
|
|
12
|
+
name: string
|
|
18
13
|
defaultState: S
|
|
19
|
-
} & ThunkModuleBase<S>
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
// The rest of the variables are doModule.
|
|
16
|
+
// Specifying index-signatures to include all the variables.
|
|
17
|
+
[action: string]: ThunkFunc<S> | string | S
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// biome-ignore lint/suspicious/noExplicitAny: ok for type utility functions.
|
|
21
|
+
export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'default' | 'defaultState'>
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
|
-
import { createReducer } from '
|
|
3
|
-
import { constructSetMap, type setMap, type setMapByModuleMap } from '
|
|
4
|
-
import type { ModuleState, State } from '
|
|
5
|
-
import type {
|
|
2
|
+
import { createReducer } from '../reducer'
|
|
3
|
+
import { constructSetMap, type setMap, type setMapByModuleMap } from '../set'
|
|
4
|
+
import type { ModuleState, State } from '../states'
|
|
5
|
+
import type { doModule, ThunkModule } from '../thunkModule'
|
|
6
6
|
import useThunkReducer from './useThunkReducer'
|
|
7
7
|
|
|
8
8
|
// biome-ignore lint/suspicious/noExplicitAny: SET_MAP_BY_MODULE can by any type
|
|
9
9
|
const SET_MAP_BY_MODULE: setMapByModuleMap<any, any> = {}
|
|
10
10
|
|
|
11
|
-
export type UseThunk<S extends State, R extends
|
|
11
|
+
export type UseThunk<S extends State, R extends doModule<S>> = [Readonly<ModuleState<S>>, setMap<S, R>]
|
|
12
12
|
|
|
13
13
|
/**********
|
|
14
14
|
* useThunk
|
|
15
15
|
**********/
|
|
16
|
-
export default <S extends State, R extends
|
|
17
|
-
theDo
|
|
18
|
-
): UseThunk<S, R> => {
|
|
19
|
-
const { name: propsName, myClass } = theDo
|
|
20
|
-
const name = (propsName ? propsName : myClass) || ''
|
|
16
|
+
export default <S extends State, R extends doModule<S>>(theDo: ThunkModule<S>): UseThunk<S, R> => {
|
|
17
|
+
const { name } = theDo
|
|
21
18
|
|
|
22
19
|
// 1. It requires shared nodes for the same module to have the same setMap.
|
|
23
20
|
const isFirstTime = !SET_MAP_BY_MODULE[name]
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
//https://github.com/nathanbuchar/react-hook-thunk-reducer/blob/master/src/thunk-reducer.js
|
|
3
3
|
|
|
4
4
|
import { useCallback, useContext } from 'react'
|
|
5
|
-
import type BaseAction from '
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
9
|
-
import {
|
|
5
|
+
import type { BaseAction } from '../action'
|
|
6
|
+
import { upsert } from '../defaultThunks/upsert'
|
|
7
|
+
import type { dispatch } from '../dispatch'
|
|
8
|
+
import type { get, getOrNull } from '../get'
|
|
9
|
+
import type { Reducer } from '../reducer'
|
|
10
|
+
import type { set } from '../set'
|
|
11
|
+
import { getStateByModule, getStateOrNullByModule, type ModuleState, type State } from '../states'
|
|
12
|
+
import { THUNK_CONTEXT_MAP } from '../thunkContext'
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* useThunkReducer
|
|
@@ -20,7 +23,7 @@ export default <S extends State>(reducer: Reducer<S>, moduleName: string): [Modu
|
|
|
20
23
|
const { refModuleState, setModuleState: setModuleState_c } = useContext(context)
|
|
21
24
|
const getModuleState = useCallback(() => {
|
|
22
25
|
return refModuleState.current
|
|
23
|
-
}, [refModuleState])
|
|
26
|
+
}, [refModuleState]) as () => ModuleState<S>
|
|
24
27
|
|
|
25
28
|
const setModuleState = useCallback(
|
|
26
29
|
(newModuleState: ModuleState<S>) => {
|
|
@@ -30,7 +33,24 @@ export default <S extends State>(reducer: Reducer<S>, moduleName: string): [Modu
|
|
|
30
33
|
[refModuleState, setModuleState_c],
|
|
31
34
|
)
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
const getOrNull: getOrNull<S> = useCallback(
|
|
37
|
+
(id?: string) => {
|
|
38
|
+
const moduleState = getModuleState()
|
|
39
|
+
const state = getStateOrNullByModule(moduleState, id)
|
|
40
|
+
return state
|
|
41
|
+
},
|
|
42
|
+
[getModuleState],
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
const get: get<S> = useCallback(
|
|
46
|
+
(id?: string) => {
|
|
47
|
+
const moduleState = getModuleState()
|
|
48
|
+
const state = getStateByModule(moduleState, id)
|
|
49
|
+
return state
|
|
50
|
+
},
|
|
51
|
+
[getModuleState],
|
|
52
|
+
)
|
|
53
|
+
|
|
34
54
|
const reduce = useCallback(
|
|
35
55
|
(action: BaseAction): ModuleState<S> => {
|
|
36
56
|
const moduleState = getModuleState()
|
|
@@ -40,12 +60,11 @@ export default <S extends State>(reducer: Reducer<S>, moduleName: string): [Modu
|
|
|
40
60
|
[reducer, getModuleState],
|
|
41
61
|
)
|
|
42
62
|
|
|
43
|
-
|
|
44
|
-
const set: set<S> = useCallback(
|
|
63
|
+
const dispatch: dispatch<S> = useCallback(
|
|
45
64
|
(action) => {
|
|
46
65
|
if (typeof action === 'function') {
|
|
47
66
|
// action is Thunk<S, A>
|
|
48
|
-
action(set, getModuleState)
|
|
67
|
+
action(set, get, getOrNull, dispatch, getModuleState)
|
|
49
68
|
return
|
|
50
69
|
}
|
|
51
70
|
|
|
@@ -56,5 +75,26 @@ export default <S extends State>(reducer: Reducer<S>, moduleName: string): [Modu
|
|
|
56
75
|
[getModuleState, setModuleState, reduce],
|
|
57
76
|
)
|
|
58
77
|
|
|
78
|
+
const set: set<S> = useCallback(
|
|
79
|
+
(actionOrID, data) => {
|
|
80
|
+
if (typeof actionOrID === 'string') {
|
|
81
|
+
// actionOrID is id
|
|
82
|
+
if (!data) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// we have the data, we can do upsert.
|
|
87
|
+
const action = upsert(actionOrID, data)
|
|
88
|
+
const newModuleState = reduce(action)
|
|
89
|
+
setModuleState(newModuleState)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// actionOrID is action
|
|
94
|
+
dispatch(actionOrID)
|
|
95
|
+
},
|
|
96
|
+
[getModuleState, setModuleState, reduce],
|
|
97
|
+
)
|
|
98
|
+
|
|
59
99
|
return [refModuleState.current, set]
|
|
60
100
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// biome-ignore lint/suspicious/noExplicitAny: obj in deepCopy can be any type.
|
|
2
|
+
const deepCopy = (obj: any): any => {
|
|
3
|
+
// Handle primitives, functions, null, or undefined
|
|
4
|
+
if (obj === null || typeof obj !== 'object') {
|
|
5
|
+
return obj
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Handle Date objects
|
|
9
|
+
if (obj instanceof Date) {
|
|
10
|
+
return new Date(obj.getTime())
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Handle Arrays
|
|
14
|
+
if (Array.isArray(obj)) {
|
|
15
|
+
return obj.map((item) => deepCopy(item))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Handle Objects
|
|
19
|
+
// biome-ignore lint/suspicious/noExplicitAny: clonedObj can be any type.
|
|
20
|
+
const clonedObj: any = {}
|
|
21
|
+
for (const key in obj) {
|
|
22
|
+
if (obj.hasOwnProperty(key)) {
|
|
23
|
+
clonedObj[key] = deepCopy(obj[key])
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return clonedObj
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default deepCopy
|
package/types/action/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ModuleState, State } from '../
|
|
1
|
+
import type { ModuleState, State } from '../states';
|
|
2
2
|
import type { ActionOrThunk } from './ActionOrThunk';
|
|
3
3
|
import type BaseAction from './baseAction';
|
|
4
4
|
import type { Thunk } from './thunk';
|
|
5
5
|
export type { Thunk, ActionOrThunk, BaseAction };
|
|
6
6
|
export type ActionFunc<S extends State> = (...params: any[]) => ActionOrThunk<S>;
|
|
7
7
|
export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>;
|
|
8
|
-
export type
|
|
8
|
+
export type getModuleState<S extends State> = () => ModuleState<S>;
|
package/types/action/thunk.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { dispatch } from '../dispatch';
|
|
2
|
+
import type { get, getOrNull } from '../get';
|
|
1
3
|
import type { set } from '../set';
|
|
2
|
-
import type { ModuleState, State } from '../
|
|
3
|
-
export type Thunk<S extends State> = (set: set<S>, getModuleState: () => ModuleState<S>) => void;
|
|
4
|
+
import type { ModuleState, State } from '../states';
|
|
5
|
+
export type Thunk<S extends State> = (set: set<S>, get: get<S>, getOrNull: getOrNull<S>, dispatch: dispatch<S>, getModuleState: () => ModuleState<S>) => void;
|