@chhsiao1981/use-thunk 12.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 +143 -80
- package/package.json +10 -16
- package/src/action/ActionOrThunk.ts +1 -1
- package/src/action/index.ts +3 -3
- package/src/action/thunk.ts +6 -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 -2
- package/src/defaultThunks/upsert.ts +27 -0
- package/src/dispatch.ts +7 -0
- package/src/get.ts +3 -2
- package/src/index.ts +43 -27
- 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} +9 -4
- 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} +6 -5
- 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 +11 -10
- package/src/{useThunk.ts → useThunk/index.ts} +6 -8
- package/src/{useThunkReducer.ts → useThunk/useThunkReducer.ts} +41 -11
- 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 -2
- package/types/defaultThunks/upsert.d.ts +5 -0
- package/types/dispatch.d.ts +4 -4
- package/types/get.d.ts +3 -2
- package/types/index.d.ts +11 -15
- 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 -1
- 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} +5 -4
- 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 +7 -9
- 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 -50
- package/src/thunkModule/defaultThunkModuleFuncMap.ts +0 -15
- 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/README.md
CHANGED
|
@@ -2,43 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://codecov.io/gh/chhsiao1981/use-thunk)
|
|
4
4
|
|
|
5
|
-
A framework easily
|
|
5
|
+
A framework for easily managing global data state with `useThunk`, with [`zustand`](https://github.com/pmndrs/zustand)-like taste.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Inspired by the concepts of [Redux Thunk](https://redux.js.org/usage/writing-logic-thunks) and [Redux Duck](https://github.com/PlatziDev/redux-duck).
|
|
8
8
|
|
|
9
|
-
[src/useThunkReducer.ts](src/useThunkReducer.ts) is
|
|
9
|
+
[src/useThunkReducer.ts](src/useThunkReducer.ts) is adapted from [nathanbuchar/react-hook-thunk-reducer](https://github.com/nathanbuchar/react-hook-thunk-reducer/blob/master/src/thunk-reducer.js).
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
For more information, please check [docs/00-introduction.md](docs/00-introduction.md).
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
2. Instead of action / reducer, we focus only on `thunk`, and have the primitive actions/reducers.
|
|
15
|
-
|
|
16
|
-
Please check [docs/00-introduction.md](docs/00-introduction.md) for more information.
|
|
17
|
-
|
|
18
|
-
Please check [demo-use-thunk](https://github.com/chhsiao1981/demo-use-thunk) for a demo to use Thunk.
|
|
19
|
-
|
|
20
|
-
### Breaking Changes
|
|
21
|
-
|
|
22
|
-
* Starting from [`12.0.0`](https://github.com/chhsiao1981/use-thunk/releases/tag/12.0.0): redefining the `getState` functions.
|
|
23
|
-
1. `getState` => `getStateOrNullByModule`, `mustGetState` => `getStateByModule`.
|
|
24
|
-
2. `mustGetStateByThunk` => `getState`.
|
|
25
|
-
* Starting from [`11.0.0`](https://github.com/chhsiao1981/use-thunk/releases/tag/11.0.0):
|
|
26
|
-
1. `setData` => `update`, `registerThunk` => `createThunk`, `dispatch` => `set`, `ClassState` => `ModuleState`, and `ModuleState.myClass` => `ModuleState.name`.
|
|
27
|
-
2. `Thunk` is `(set, get, getModuleState) => {}`, where `get(id)` directly returns object-level state.
|
|
28
|
-
* Starting from [`10.0.0`](https://github.com/chhsiao1981/use-thunk/releases/tag/10.0.0): The ClassState is shared globally, with `registerThunk` and `ThunkContext`.
|
|
29
|
-
* Starting from [`9.0.0`](https://github.com/chhsiao1981/use-thunk/releases/tag/9.0.0): npm package is renamed as [@chhsiao1981/use-thunk](https://www.npmjs.com/package/%40chhsiao1981/use-thunk)
|
|
30
|
-
* Starting from [`8.0.0`](https://github.com/chhsiao1981/use-thunk/releases/tag/8.0.0): [Totally renamed as `useThunk`](https://github.com/chhsiao1981/use-thunk/issues/105).
|
|
13
|
+
For usage examples, please refer to [demo-use-thunk](https://github.com/chhsiao1981/demo-use-thunk).
|
|
31
14
|
|
|
32
15
|
## Install
|
|
33
16
|
|
|
34
17
|
npm install --save @chhsiao1981/use-thunk
|
|
35
18
|
|
|
36
|
-
##
|
|
19
|
+
## Getting Started
|
|
37
20
|
|
|
38
|
-
Thunk module able to do increment (
|
|
21
|
+
Thunk module able to do increment (thunks/increment.ts):
|
|
39
22
|
|
|
40
23
|
```ts
|
|
41
|
-
import {
|
|
24
|
+
import { type Thunk, type State as rState, update } from '@chhsiao1981/use-thunk'
|
|
42
25
|
|
|
43
26
|
export const name = 'demo/Increment'
|
|
44
27
|
|
|
@@ -50,51 +33,53 @@ export const defaultState: State = {
|
|
|
50
33
|
count: 0
|
|
51
34
|
}
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return async (set) => {
|
|
56
|
-
|
|
36
|
+
// upsert directly with set.
|
|
37
|
+
export const increment = (myID: string, num: number = 1): Thunk<State> => {
|
|
38
|
+
return async (set, get) => {
|
|
39
|
+
let me = get(myID)
|
|
40
|
+
const {count} = me
|
|
41
|
+
|
|
42
|
+
set(myID, { count: count + num })
|
|
57
43
|
}
|
|
58
44
|
}
|
|
59
45
|
|
|
60
|
-
|
|
46
|
+
// or we can treat set as dispatching a base action.
|
|
47
|
+
export const increment2 = (myID: string): Thunk<State> => {
|
|
61
48
|
return async (set, get) => {
|
|
62
49
|
let me = get(myID)
|
|
63
|
-
if(!me) {
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
50
|
const {count} = me
|
|
67
51
|
|
|
68
|
-
set(update(
|
|
52
|
+
set(update({ count: count + 2 }))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// or we can use set as dispatching a thunk function.
|
|
57
|
+
export const increment3 = (myID: string): Thunk<State> => {
|
|
58
|
+
return async (set) => {
|
|
59
|
+
set(increment(myID, 3))
|
|
69
60
|
}
|
|
70
61
|
}
|
|
71
62
|
```
|
|
72
63
|
|
|
73
|
-
App.tsx:
|
|
64
|
+
components/App.tsx:
|
|
74
65
|
|
|
75
66
|
```tsx
|
|
76
67
|
import { type ThunkModuleToFunc, useThunk, getState } from '@chhsiao1981/use-thunk'
|
|
77
|
-
import * as DoIncrement from './
|
|
68
|
+
import * as DoIncrement from './thunks/increment'
|
|
78
69
|
|
|
79
|
-
type
|
|
70
|
+
type doIncrement = toDoModule(typeof DoIncrement)
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
export default (props: Props) => {
|
|
85
|
-
const useIncrement = useThunk<DoIncrement.State, TDoIncrement>(DoIncrement, StateType.LOCAL)
|
|
72
|
+
export default () => {
|
|
73
|
+
const useIncrement = useThunk<DoIncrement.State, doIncrement>(DoIncrement)
|
|
86
74
|
const [increment, doIncrement, incrementID] = getState(useIncrement)
|
|
87
75
|
|
|
88
|
-
//init
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
doIncrement.init()
|
|
91
|
-
}, [])
|
|
92
|
-
|
|
93
76
|
// to render
|
|
94
77
|
return (
|
|
95
78
|
<div>
|
|
96
79
|
<p>count: {increment.count}</p>
|
|
97
|
-
<button onClick={() => doIncrement.increment(incrementID)}>increase</button>
|
|
80
|
+
<button onClick={() => doIncrement.increment(incrementID)}>increase 1</button>
|
|
81
|
+
<button onClick={() => doIncrement.increment2(incrementID)}>increase 2</button>
|
|
82
|
+
<button onClick={() => doIncrement.increment3(incrementID)}>increase 3</button>
|
|
98
83
|
</div>
|
|
99
84
|
)
|
|
100
85
|
}
|
|
@@ -102,13 +87,13 @@ export default (props: Props) => {
|
|
|
102
87
|
|
|
103
88
|
main.tsx:
|
|
104
89
|
```tsx
|
|
105
|
-
import {
|
|
90
|
+
import { registerThunk, ThunkContext } from "@chhsiao1981/use-thunk";
|
|
106
91
|
import { StrictMode } from "react";
|
|
107
92
|
import { createRoot } from "react-dom/client";
|
|
108
|
-
import * as DoIncrement from './
|
|
109
|
-
import App from "./App
|
|
93
|
+
import * as DoIncrement from './thunks/increment'
|
|
94
|
+
import App from "./components/App";
|
|
110
95
|
|
|
111
|
-
|
|
96
|
+
registerThunk(DoIncrement)
|
|
112
97
|
|
|
113
98
|
createRoot(document.getElementById("root")!).render(
|
|
114
99
|
<StrictMode>
|
|
@@ -119,6 +104,11 @@ createRoot(document.getElementById("root")!).render(
|
|
|
119
104
|
)
|
|
120
105
|
```
|
|
121
106
|
|
|
107
|
+
## Introduction
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## Development Pattern
|
|
122
112
|
### Must Included in a Thunk Module
|
|
123
113
|
|
|
124
114
|
```ts
|
|
@@ -138,29 +128,30 @@ export const defaultState: State = {}
|
|
|
138
128
|
.
|
|
139
129
|
```
|
|
140
130
|
|
|
141
|
-
### Must Included in a
|
|
131
|
+
### Must Included in a Statically-allocated (always allocated) Component
|
|
142
132
|
|
|
143
133
|
```ts
|
|
144
|
-
import { type
|
|
145
|
-
import * as DoModule from '../
|
|
134
|
+
import { type toDoModule, useThunk, getState } from '@chhsiao1981/use-thunk'
|
|
135
|
+
import * as DoModule from '../thunks/module'
|
|
146
136
|
|
|
147
|
-
type
|
|
137
|
+
type doModule = toDoModule<typeof DoModule>
|
|
148
138
|
|
|
149
139
|
const Component = () => {
|
|
150
|
-
const useModule = useThunk<DoModule.State,
|
|
140
|
+
const useModule = useThunk<DoModule.State, doModule>(DoModule)
|
|
151
141
|
const [module, doModule, moduleID] = getState(useModule)
|
|
152
142
|
|
|
153
143
|
.
|
|
154
|
-
|
|
155
|
-
|
|
144
|
+
.
|
|
145
|
+
.
|
|
156
146
|
}
|
|
157
147
|
```
|
|
158
148
|
|
|
159
|
-
### Must Included in main.tsx
|
|
149
|
+
### Must Included in `main.tsx`
|
|
160
150
|
|
|
161
151
|
```tsx
|
|
162
|
-
import {
|
|
163
|
-
|
|
152
|
+
import { registerThunk, ThunkContext } from '@chhsiao1981/use-thunk'
|
|
153
|
+
import * as DoModule from '../thunks/module'
|
|
154
|
+
registerThunk(DoModule)
|
|
164
155
|
.
|
|
165
156
|
.
|
|
166
157
|
.
|
|
@@ -292,47 +283,112 @@ moduleStateUser = {
|
|
|
292
283
|
|
|
293
284
|
## [APIs](https://github.com/chhsiao1981/use-thunk/blob/main/src/index.d.ts)
|
|
294
285
|
|
|
295
|
-
|
|
286
|
+
#### Types
|
|
296
287
|
|
|
297
|
-
##### `
|
|
288
|
+
##### `type Thunk`
|
|
298
289
|
|
|
299
|
-
|
|
290
|
+
`Thunk` is defined as:
|
|
300
291
|
|
|
301
|
-
|
|
292
|
+
```ts
|
|
293
|
+
export type Thunk<S extends State> = (
|
|
294
|
+
set: set<S>,
|
|
295
|
+
get: (id?: string) => S,
|
|
296
|
+
getOrNull: (id?: string) => S | null | undefined,
|
|
297
|
+
dispatch: dispatch<S>,
|
|
298
|
+
getModuleState: () => ModuleState<S>,
|
|
299
|
+
) => void
|
|
300
|
+
```
|
|
302
301
|
|
|
303
|
-
|
|
302
|
+
We generally use only `set` and `get`.
|
|
304
303
|
|
|
305
|
-
##### `
|
|
304
|
+
##### `ThunkModule<S extends State>`
|
|
306
305
|
|
|
307
|
-
|
|
306
|
+
```ts
|
|
307
|
+
export type ThunkModule<S extends State> = {
|
|
308
|
+
name: string
|
|
309
|
+
defaultState: S
|
|
308
310
|
|
|
309
|
-
|
|
311
|
+
// The rest of the variables are doModule.
|
|
312
|
+
// Specifying index-signatures to include all the variables.
|
|
313
|
+
[action: string]: ThunkFunc<S> | string | S
|
|
314
|
+
}
|
|
315
|
+
```
|
|
310
316
|
|
|
311
|
-
|
|
317
|
+
##### `doModule<S extends State>`
|
|
312
318
|
|
|
313
|
-
|
|
319
|
+
```ts
|
|
320
|
+
export interface doModule<S extends State> {
|
|
321
|
+
[action: string]: ThunkFunc<S>
|
|
322
|
+
}
|
|
323
|
+
```
|
|
314
324
|
|
|
315
|
-
|
|
325
|
+
##### `ThunkFunc<S extends State>`
|
|
316
326
|
|
|
317
|
-
|
|
327
|
+
```ts
|
|
328
|
+
export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>
|
|
329
|
+
```
|
|
318
330
|
|
|
319
|
-
|
|
331
|
+
#### RegisterThunk / ThunkContext / useThunk
|
|
320
332
|
|
|
321
|
-
##### `
|
|
333
|
+
##### `registerThunk(module: ThunkModule)`
|
|
322
334
|
|
|
323
|
-
|
|
335
|
+
register a thunk module.
|
|
336
|
+
|
|
337
|
+
##### `<ThunkContext>{children}</ThunkContext>`
|
|
324
338
|
|
|
325
|
-
|
|
339
|
+
Rendering thunk context.
|
|
326
340
|
|
|
327
|
-
|
|
341
|
+
##### `useThunk(theDo: ThunkModule): UseThunk`
|
|
342
|
+
|
|
343
|
+
Similar to `React.useReducer`, but we use `useThunk`, and we also bind the actions with `set` (similar concept as `mapDispatchToProps`).
|
|
344
|
+
|
|
345
|
+
return: `UseThunk`
|
|
328
346
|
|
|
329
|
-
|
|
347
|
+
#### State
|
|
330
348
|
|
|
331
349
|
##### `getState(theUseThunk: UseThunk, myID?: string): [state, doModule, theID]`
|
|
332
350
|
|
|
333
351
|
Get the state of `myID` by `UseThunk`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
|
|
334
352
|
|
|
335
353
|
return: `[state, doModule, theID]`
|
|
354
|
+
o
|
|
355
|
+
### Advanced Usage
|
|
356
|
+
|
|
357
|
+
#### types
|
|
358
|
+
|
|
359
|
+
##### `UseThunk`
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
export type UseThunk<S extends State, R extends doModule<S>> = [Readonly<ModuleState<S>>, setMap<S, R>]
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
##### `setMap`
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
export type setMap<S extends State, T extends doModule<S>> = {
|
|
369
|
+
[action in keyof T]: VoidReturnType<T[action]>
|
|
370
|
+
} & Omit<DefaultSetMap, keyof T>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### Default Thunk Functions.
|
|
374
|
+
|
|
375
|
+
##### `init({myID, parentID, doParent, state})`
|
|
376
|
+
|
|
377
|
+
initialize the state.
|
|
378
|
+
|
|
379
|
+
##### `update(myID, data)`
|
|
380
|
+
|
|
381
|
+
update the data to myID.
|
|
382
|
+
|
|
383
|
+
##### `upsert(myID, data)`
|
|
384
|
+
|
|
385
|
+
initialize the state if it does not exist, and update the data to myID.
|
|
386
|
+
|
|
387
|
+
##### `remove(myID)`
|
|
388
|
+
|
|
389
|
+
remove the state.
|
|
390
|
+
|
|
391
|
+
#### State
|
|
336
392
|
|
|
337
393
|
##### `getStateOrNullByModule(moduleState: ModuleState, myID?: string): state | null`
|
|
338
394
|
|
|
@@ -341,3 +397,10 @@ Get the state of `myID`. Get the state of `defaultID` if `myID` is not present.
|
|
|
341
397
|
##### `getStateByModule(moduleState: ModuleState, myID?: string): state`
|
|
342
398
|
|
|
343
399
|
Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
|
|
400
|
+
|
|
401
|
+
#### Misc
|
|
402
|
+
|
|
403
|
+
##### `genID(): string`
|
|
404
|
+
|
|
405
|
+
generate id for the state.
|
|
406
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chhsiao1981/use-thunk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A framework easily using useThunk to manage the data-state.",
|
|
6
6
|
"homepage": "https://github.com/chhsiao1981/use-thunk",
|
|
@@ -36,28 +36,22 @@
|
|
|
36
36
|
},
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@codecov/vite-plugin": "^
|
|
40
|
-
"@
|
|
41
|
-
"@types/node": "^25.5.0",
|
|
39
|
+
"@codecov/vite-plugin": "^2.0.1",
|
|
40
|
+
"@types/node": "^25.9.3",
|
|
42
41
|
"@types/react": ">=18.3.1",
|
|
43
42
|
"@types/react-dom": ">=18.3.1",
|
|
44
|
-
"@vitejs/plugin-react-swc": "^4.3.
|
|
45
|
-
"@vitest/coverage-v8": "^4.1.
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"globals": "^17.4.0",
|
|
50
|
-
"happy-dom": "^20.8.4",
|
|
51
|
-
"jiti": "^2.6.1",
|
|
43
|
+
"@vitejs/plugin-react-swc": "^4.3.1",
|
|
44
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
45
|
+
"globals": "^17.6.0",
|
|
46
|
+
"happy-dom": "^20.10.2",
|
|
47
|
+
"jiti": "^2.7.0",
|
|
52
48
|
"react-dom": ">=18.3.1",
|
|
53
49
|
"rimraf": "^6.1.3",
|
|
54
50
|
"typescript": "~5.9.3",
|
|
55
|
-
"typescript-eslint": "^8.57.1",
|
|
56
51
|
"vite": "^6.4.1",
|
|
57
|
-
"vitest": "^4.1.
|
|
52
|
+
"vitest": "^4.1.8"
|
|
58
53
|
},
|
|
59
54
|
"peerDependencies": {
|
|
60
|
-
"react": ">=18.3.1"
|
|
61
|
-
"uuid": "^14.0.0"
|
|
55
|
+
"react": ">=18.3.1"
|
|
62
56
|
}
|
|
63
57
|
}
|
package/src/action/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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'
|
|
@@ -12,5 +12,5 @@ export type ActionFunc<S extends State> = (...params: any[]) => ActionOrThunk<S>
|
|
|
12
12
|
// biome-ignore lint/suspicious/noExplicitAny: params can by any type.
|
|
13
13
|
export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>
|
|
14
14
|
|
|
15
|
-
//
|
|
16
|
-
export type
|
|
15
|
+
// getModuleState
|
|
16
|
+
export type getModuleState<S extends State> = () => ModuleState<S>
|
package/src/action/thunk.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
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 '../
|
|
4
|
+
import type { ModuleState, State } from '../states'
|
|
3
5
|
|
|
4
6
|
// Thunk
|
|
5
7
|
export type Thunk<S extends State> = (
|
|
6
8
|
set: set<S>,
|
|
7
|
-
get:
|
|
9
|
+
get: get<S>,
|
|
10
|
+
getOrNull: getOrNull<S>,
|
|
11
|
+
dispatch: dispatch<S>,
|
|
8
12
|
getModuleState: () => ModuleState<S>,
|
|
9
13
|
) => void
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// default thunks will be used in thunkModule/defaultDoModule and defaultReduceMap
|
|
2
|
+
import { INIT, type InitParams, init, reduceInit } from './init'
|
|
3
|
+
export { INIT, type InitParams, init, reduceInit }
|
|
4
|
+
|
|
5
|
+
import { reduceUpdate, UPDATE, update } from './update'
|
|
6
|
+
export { reduceUpdate, UPDATE, update }
|
|
7
|
+
|
|
8
|
+
import { REMOVE, reduceRemove, remove } from './remove'
|
|
9
|
+
export { REMOVE, reduceRemove, remove }
|
|
10
|
+
|
|
11
|
+
import { reduceUpsert, UPSERT, upsert } from './upsert'
|
|
12
|
+
export { UPSERT, upsert, reduceUpsert }
|
|
13
|
+
|
|
14
|
+
import { reduceSetDefaultID, SET_DEFAULT_ID, setDefaultID } from './setDefaultID'
|
|
15
|
+
export { SET_DEFAULT_ID, setDefaultID, reduceSetDefaultID }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Thunk } from '../../action'
|
|
2
|
+
import type { State } from '../../states'
|
|
3
|
+
import { genID } from '../../utils'
|
|
4
|
+
import { setDefaultID } from '../setDefaultID'
|
|
5
|
+
import initCore, { INIT, reduceInit } from './initCore'
|
|
6
|
+
export { INIT, reduceInit }
|
|
7
|
+
|
|
8
|
+
// InitParams
|
|
9
|
+
export interface InitParams<S extends State> {
|
|
10
|
+
myID?: string
|
|
11
|
+
state: S
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const init = <S extends State>(params: InitParams<S>): Thunk<S> => {
|
|
15
|
+
return (set, _get, _getOrNull, _dispatch, getModuleState) => {
|
|
16
|
+
const myID = params.myID ?? genID()
|
|
17
|
+
|
|
18
|
+
const { state } = params
|
|
19
|
+
set(initCore(myID, state))
|
|
20
|
+
|
|
21
|
+
const { defaultID } = getModuleState()
|
|
22
|
+
|
|
23
|
+
if (!defaultID) {
|
|
24
|
+
set(setDefaultID(myID))
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type BaseAction from '
|
|
2
|
-
import type { ModuleState, NodeState, NodeStateMap, State } from '
|
|
1
|
+
import type { BaseAction } from '../../action'
|
|
2
|
+
import type { ModuleState, NodeState, NodeStateMap, State } from '../../states'
|
|
3
3
|
|
|
4
4
|
export interface InitAction<S extends State> extends BaseAction {
|
|
5
5
|
state: S
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type BaseAction from '
|
|
2
|
-
import type { ModuleState, NodeStateMap, State } from '
|
|
1
|
+
import type { BaseAction } from '../action'
|
|
2
|
+
import type { ModuleState, NodeStateMap, State } from '../states'
|
|
3
3
|
|
|
4
4
|
export const REMOVE = '@chhsiao1981/use-thunk/REMOVE'
|
|
5
5
|
export const remove = (myID: string): BaseAction => ({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type BaseAction from '
|
|
2
|
-
import type { ModuleState, State } from '
|
|
1
|
+
import type { BaseAction } from '../action'
|
|
2
|
+
import type { ModuleState, State } from '../states'
|
|
3
3
|
|
|
4
4
|
export const SET_DEFAULT_ID = '@chhsiao1981/use-thunk/SET_DEFAULT_ID'
|
|
5
5
|
export const setDefaultID = (myID: string): BaseAction => ({
|
|
@@ -13,5 +13,6 @@ export const reduceSetDefaultID = <S extends State>(
|
|
|
13
13
|
): ModuleState<S> => {
|
|
14
14
|
const { myID } = action
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const toUpdate: Partial<ModuleState<S>> = { defaultID: myID, isInitDefaultID: true }
|
|
17
|
+
return Object.assign({}, moduleState, toUpdate)
|
|
17
18
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type BaseAction from '
|
|
2
|
-
import type { ModuleState, State } from '
|
|
1
|
+
import type { BaseAction } from '../action'
|
|
2
|
+
import type { ModuleState, State } from '../states'
|
|
3
3
|
|
|
4
4
|
export const UPDATE = '@chhsiao1981/use-thunk/UPDATE'
|
|
5
5
|
export const update = <S extends State>(myID: string, data: Partial<S>): BaseAction => ({
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BaseAction } from '../action'
|
|
2
|
+
import type { ModuleState, NodeState, State } from '../states'
|
|
3
|
+
import { deepCopy } from '../utils'
|
|
4
|
+
|
|
5
|
+
export const UPSERT = '@chhsiao1981/use-thunk/UPSERT'
|
|
6
|
+
export const upsert = <S extends State>(myID: string, data: Partial<S>): BaseAction => ({
|
|
7
|
+
myID,
|
|
8
|
+
type: UPSERT,
|
|
9
|
+
data,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export const reduceUpsert = <S extends State>(
|
|
13
|
+
moduleState: ModuleState<S>,
|
|
14
|
+
action: BaseAction,
|
|
15
|
+
): ModuleState<S> => {
|
|
16
|
+
const { myID, data } = action
|
|
17
|
+
|
|
18
|
+
const myNode = moduleState.nodes[myID]
|
|
19
|
+
const node: NodeState<S> = myNode ?? { id: myID, state: deepCopy(moduleState.defaultState) }
|
|
20
|
+
|
|
21
|
+
const newState = Object.assign({}, node.state, data)
|
|
22
|
+
const newNode = Object.assign({}, node, { state: newState })
|
|
23
|
+
const newNodes = Object.assign({}, moduleState.nodes, { [myID]: newNode })
|
|
24
|
+
const newModuleState = Object.assign({}, moduleState, { nodes: newNodes })
|
|
25
|
+
|
|
26
|
+
return newModuleState
|
|
27
|
+
}
|
package/src/dispatch.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Dispatch } from 'react'
|
|
2
|
+
// XXX requiring to import directly from action/ActionOrThunk, or it will cause looping.
|
|
3
|
+
import type { ActionOrThunk } from './action'
|
|
4
|
+
import type { State } from './states'
|
|
5
|
+
|
|
6
|
+
// dispatch
|
|
7
|
+
export type dispatch<S extends State> = Dispatch<ActionOrThunk<S>>
|
package/src/get.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type { State } from './
|
|
1
|
+
import type { State } from './states'
|
|
2
2
|
|
|
3
|
-
export type get
|
|
3
|
+
export type get<S extends State> = (id?: string) => S
|
|
4
|
+
export type getOrNull<S extends State> = (id?: string) => S | null | undefined
|
package/src/index.ts
CHANGED
|
@@ -1,42 +1,58 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import type { get } from './get'
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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'
|
|
15
18
|
import useThunk, { type UseThunk } from './useThunk'
|
|
19
|
+
import { genID } from './utils'
|
|
16
20
|
|
|
17
21
|
export {
|
|
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 Thunk,
|
|
38
|
+
// module related.
|
|
26
39
|
type ThunkModule,
|
|
27
|
-
type
|
|
28
|
-
type
|
|
29
|
-
type
|
|
30
|
-
|
|
31
|
-
getNode,
|
|
32
|
-
getDefaultID,
|
|
33
|
-
getStateOrNullByModule,
|
|
34
|
-
getStateByModule,
|
|
35
|
-
getState,
|
|
40
|
+
type toDoModule,
|
|
41
|
+
type doModule,
|
|
42
|
+
type ThunkFunc,
|
|
43
|
+
// default thunks.
|
|
36
44
|
init,
|
|
37
45
|
type InitParams,
|
|
38
46
|
update,
|
|
47
|
+
upsert,
|
|
39
48
|
remove,
|
|
49
|
+
// genID
|
|
50
|
+
genID,
|
|
51
|
+
// advanced usage.
|
|
52
|
+
type setMap,
|
|
40
53
|
setDefaultID,
|
|
41
|
-
|
|
54
|
+
getNodeOrNull,
|
|
55
|
+
getDefaultID,
|
|
56
|
+
getStateOrNullByModule,
|
|
57
|
+
getStateByModule,
|
|
42
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
|
+
}
|