@chhsiao1981/use-thunk 12.0.0 → 14.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.
Files changed (101) hide show
  1. package/README.md +211 -122
  2. package/{types → dist}/action/ActionOrThunk.d.ts +1 -1
  3. package/{types → dist}/action/index.d.ts +2 -2
  4. package/dist/action/thunk.d.ts +5 -0
  5. package/dist/defaultThunks/index.d.ts +10 -0
  6. package/dist/defaultThunks/init/index.d.ts +9 -0
  7. package/{types → dist/defaultThunks}/init/initCore.d.ts +2 -2
  8. package/{types → dist/defaultThunks}/remove.d.ts +2 -2
  9. package/{types → dist/defaultThunks}/setDefaultID.d.ts +2 -2
  10. package/{types → dist/defaultThunks}/update.d.ts +2 -2
  11. package/dist/defaultThunks/upsert.d.ts +5 -0
  12. package/dist/dispatch.d.ts +3 -3
  13. package/dist/get.d.ts +3 -0
  14. package/dist/index.d.ts +11 -14
  15. package/dist/index.js +173 -0
  16. package/dist/index.umd.cjs +1 -0
  17. package/dist/reducer/createReducer.d.ts +3 -0
  18. package/dist/reducer/defaultReduceMap.d.ts +2 -0
  19. package/{types/reducer.d.ts → dist/reducer/index.d.ts} +4 -2
  20. package/dist/reducer/reduceMap.d.ts +5 -0
  21. package/{types/createThunk.d.ts → dist/registerThunk.d.ts} +1 -1
  22. package/dist/set/index.d.ts +5 -0
  23. package/dist/set/setMap.d.ts +16 -0
  24. package/dist/states/index.d.ts +10 -0
  25. package/{types/stateTypes.d.ts → dist/states/types.d.ts} +5 -4
  26. package/dist/thunkContext/ThunkContext.d.ts +7 -0
  27. package/dist/thunkContext/index.d.ts +6 -0
  28. package/{types → dist/thunkContext}/thunkContextMap.d.ts +2 -2
  29. package/{types/thunkContextTypes.d.ts → dist/thunkContext/types.d.ts} +1 -1
  30. package/dist/thunkModule/defaultDoModule.d.ts +5 -0
  31. package/dist/thunkModule/index.d.ts +13 -0
  32. package/dist/useThunk/index.d.ts +9 -0
  33. package/{types → dist/useThunk}/useThunkReducer.d.ts +3 -3
  34. package/dist/utils/deepCopy.d.ts +2 -0
  35. package/dist/utils/genID.d.ts +1 -0
  36. package/dist/utils/index.d.ts +3 -0
  37. package/package.json +35 -30
  38. package/dist/ThunkContext.d.ts +0 -7
  39. package/dist/action.d.ts +0 -11
  40. package/dist/createReducer.d.ts +0 -4
  41. package/dist/createThunk.d.ts +0 -4
  42. package/dist/dispatchFuncMap.d.ts +0 -18
  43. package/dist/genUUID.d.ts +0 -1
  44. package/dist/init.d.ts +0 -16
  45. package/dist/reduceMap.d.ts +0 -6
  46. package/dist/reducer.d.ts +0 -5
  47. package/dist/remove.d.ts +0 -5
  48. package/dist/setDefaultID.d.ts +0 -5
  49. package/dist/stateTypes.d.ts +0 -16
  50. package/dist/states.d.ts +0 -9
  51. package/dist/thunk.d.ts +0 -15
  52. package/dist/thunkContextMap.d.ts +0 -15
  53. package/dist/thunkContextTypes.d.ts +0 -8
  54. package/dist/thunkModuleFuncMap.d.ts +0 -7
  55. package/dist/update.d.ts +0 -6
  56. package/dist/useThunk.d.ts +0 -12
  57. package/dist/useThunkReducer.d.ts +0 -17
  58. package/src/ThunkContext.tsx +0 -46
  59. package/src/action/ActionOrThunk.ts +0 -5
  60. package/src/action/baseAction.ts +0 -6
  61. package/src/action/index.ts +0 -16
  62. package/src/action/thunk.ts +0 -9
  63. package/src/createReducer.ts +0 -24
  64. package/src/createThunk.ts +0 -24
  65. package/src/genUUID.ts +0 -38
  66. package/src/get.ts +0 -3
  67. package/src/index.ts +0 -42
  68. package/src/init/index.ts +0 -26
  69. package/src/init/initCore.ts +0 -31
  70. package/src/reduceMap.ts +0 -22
  71. package/src/reducer.ts +0 -9
  72. package/src/remove.ts +0 -35
  73. package/src/set.ts +0 -7
  74. package/src/setDefaultID.ts +0 -17
  75. package/src/setMap.ts +0 -65
  76. package/src/stateTypes.ts +0 -22
  77. package/src/states.ts +0 -50
  78. package/src/thunkContextMap.ts +0 -22
  79. package/src/thunkContextTypes.ts +0 -8
  80. package/src/thunkModule/defaultThunkModuleFuncMap.ts +0 -15
  81. package/src/thunkModule/index.ts +0 -20
  82. package/src/update.ts +0 -26
  83. package/src/useThunk.ts +0 -50
  84. package/src/useThunkReducer.ts +0 -70
  85. package/types/ThunkContext.d.ts +0 -7
  86. package/types/action/thunk.d.ts +0 -3
  87. package/types/createReducer.d.ts +0 -4
  88. package/types/dispatch.d.ts +0 -4
  89. package/types/dispatchFuncMap.d.ts +0 -17
  90. package/types/genUUID.d.ts +0 -1
  91. package/types/get.d.ts +0 -2
  92. package/types/index.d.ts +0 -16
  93. package/types/init/index.d.ts +0 -7
  94. package/types/reduceMap.d.ts +0 -6
  95. package/types/set.d.ts +0 -4
  96. package/types/setMap.d.ts +0 -17
  97. package/types/states.d.ts +0 -9
  98. package/types/thunkModule/defaultThunkModuleFuncMap.d.ts +0 -5
  99. package/types/thunkModule/index.d.ts +0 -15
  100. package/types/useThunk.d.ts +0 -9
  101. /package/{types → dist}/action/baseAction.d.ts +0 -0
package/README.md CHANGED
@@ -2,43 +2,26 @@
2
2
 
3
3
  [![codecov](https://codecov.io/gh/chhsiao1981/use-thunk/branch/main/graph/badge.svg)](https://codecov.io/gh/chhsiao1981/use-thunk)
4
4
 
5
- A framework easily using `useThunk` to manage the data-state.
5
+ A framework for easily managing global data state with `useThunk`, with [`zustand`](https://github.com/pmndrs/zustand)-like taste.
6
6
 
7
- Adopted concept of [redux-thunk](https://redux.js.org/usage/writing-logic-thunks) and [redux-duck](https://github.com/PlatziDev/redux-duck)
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 adopted from [nathanbuchar/react-hook-thunk-reducer](https://github.com/nathanbuchar/react-hook-thunk-reducer/blob/master/src/thunk-reducer.js).
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
- `use-thunk` is with the following additional features:
11
+ For more information, please check [docs/00-introduction.md](docs/00-introduction.md).
12
12
 
13
- 1. The development of the thunk modules follows the concept of `redux-duck`.
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
- npm install --save @chhsiao1981/use-thunk
17
+ npm install @chhsiao1981/use-thunk
35
18
 
36
- ## Example
19
+ ## Getting Started
37
20
 
38
- Thunk module able to do increment (reducers/increment.ts):
21
+ Thunk module able to do increment (thunks/increment.ts):
39
22
 
40
23
  ```ts
41
- import { init as _init, update, Thunk, type State as rState, genUUID } from '@chhsiao1981/use-thunk'
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
- export const init = (): Thunk<State> => {
54
- const myID = genUUID()
55
- return async (set) => {
56
- set(_init({myID, state: defaultState}))
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
- export const increment = (myID: string): Thunk<State> => {
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(myID, { count: count + 1 }))
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 './reducers/increment'
68
+ import * as DoIncrement from './thunks/increment'
78
69
 
79
- type TDoIncrement = ThunkModuleToFunc(typeof DoIncrement)
70
+ type doIncrement = toDoModule(typeof DoIncrement)
80
71
 
81
- type Props = {
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 { createThunk, ThunkContext } from "@chhsiao1981/use-thunk";
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 './reducers/increment'
109
- import App from "./App.tsx";
93
+ import * as DoIncrement from './thunks/increment'
94
+ import App from "./components/App";
110
95
 
111
- createThunk(DoIncrement)
96
+ registerThunk(DoIncrement)
112
97
 
113
98
  createRoot(document.getElementById("root")!).render(
114
99
  <StrictMode>
@@ -119,6 +104,7 @@ createRoot(document.getElementById("root")!).render(
119
104
  )
120
105
  ```
121
106
 
107
+ ## Development Pattern
122
108
  ### Must Included in a Thunk Module
123
109
 
124
110
  ```ts
@@ -138,29 +124,30 @@ export const defaultState: State = {}
138
124
  .
139
125
  ```
140
126
 
141
- ### Must Included in a Top-level Component
127
+ ### Must Included in a Statically-allocated (always allocated) Component
142
128
 
143
129
  ```ts
144
- import { type ThunkModuleToFunc, useThunk, getState } from '@chhsiao1981/use-thunk'
145
- import * as DoModule from '../reducers/module'
130
+ import { type toDoModule, useThunk, getState } from '@chhsiao1981/use-thunk'
131
+ import * as DoModule from '../thunks/module'
146
132
 
147
- type TDoModule = ThunkModuleToFunc<typeof DoModule>
133
+ type doModule = toDoModule<typeof DoModule>
148
134
 
149
135
  const Component = () => {
150
- const useModule = useThunk<DoModule.State, TDoModule>(DoModule)
136
+ const useModule = useThunk<DoModule.State, doModule>(DoModule)
151
137
  const [module, doModule, moduleID] = getState(useModule)
152
138
 
153
139
  .
154
- .
155
- .
140
+ .
141
+ .
156
142
  }
157
143
  ```
158
144
 
159
- ### Must Included in main.tsx
145
+ ### Must Included in `main.tsx`
160
146
 
161
147
  ```tsx
162
- import { createThunk, ThunkContext } from '@chhsiao1981/use-thunk'
163
- createThunk(...)
148
+ import { registerThunk, ThunkContext } from '@chhsiao1981/use-thunk'
149
+ import * as DoModule from '../thunks/module'
150
+ registerThunk(DoModule)
164
151
  .
165
152
  .
166
153
  .
@@ -174,14 +161,23 @@ createRoot(document.getElementById("root")!).render(
174
161
  )
175
162
  ```
176
163
 
177
- ## Normalized State
164
+ ## Introduction
165
+
166
+ Global state management (GSM) is tricky when developing complex ReactJS applications. [Redux/RTK](https://redux-toolkit.js.org/) and [zustand](https://zustand-demo.pmnd.rs/) focus on "We create stores that manage the global states". However, the stores can quickly become gigantic functions in complex ReacJS applications. On the other hand, `useContext` is too primitive for complex ReactJS applications.
167
+
168
+ `use-thunk` uses a different approach: All the data management is through module-based functions. With `use-thunk`:
169
+ 1. We treat the files as modules, and we write the module-based functions like what we typically do in other programming languages.
170
+ 2. React components can focus on data presentation, with obtaining the data from thunk modules.
171
+ 3. From React components' perspective, we directly call `do[Module].function(id)`.
172
+ 4. There is only 1 `ThunkContext`, which wraps around `<App />` in `main.tsx`. We no longer need to worry that the `Context` may appear in unexpected code-base and affect the underlying `useContext`.
173
+
174
+ ### Normalized State
178
175
 
179
- The general concept of normalized state can be found in [Normalizing State Shape](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape)
180
- with the following features:
176
+ The general concept of normalized state can be found in [Normalizing State Shape](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape). We use the following hierarchy to represent the normalized states:
181
177
 
182
- 1. ClassState: the state of the class, including the nodes and the defaultID of the class.
183
- 2. NodeState: the state of a node, including the id of the node and the content (state) of the node.
184
- 3. State: the content of the node, represented as a state.
178
+ 1. ModuleState: the state of a module, including the nodes and related information of the module.
179
+ 2. NodeState: the state of a node, including the id of the node and the data (state) of the node.
180
+ 3. State: the data of the node, represented as a state.
185
181
 
186
182
  For example, the example [in the redux link](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape) is represented as:
187
183
 
@@ -189,24 +185,24 @@ For example, the example [in the redux link](https://redux.js.org/recipes/struct
189
185
  moduleStatePost = {
190
186
  name: 'post',
191
187
  nodes: {
192
- [uuid-post1] : {
193
- id: uuid-post1,
188
+ [postID1] : {
189
+ id: postID1,
194
190
  state: {
195
- author : uuid-user1,
191
+ author : userID1,
196
192
  body : "......",
197
- comments: [uuid-comment1, uuid-comment2]
193
+ comments: [commentID1, commentID2]
198
194
  },
199
195
  },
200
- [uuid-post2] : {
201
- id : uuid-post2,
196
+ [postID2] : {
197
+ id : postID2,
202
198
  state: {
203
- author : uuid-user2,
199
+ author : userID2,
204
200
  body : "......",
205
- comments: [uuid-comment3, uuid-comment4, uuid-comment5]
201
+ comments: [commentID3, commentID4, commentID5]
206
202
  }
207
203
  }
208
204
  },
209
- defaultID,s
205
+ defaultID,
210
206
  defaultState,
211
207
  }
212
208
  ```
@@ -215,40 +211,40 @@ and:
215
211
 
216
212
  ```ts
217
213
  moduleStateComment = {
218
- myClass: 'module',
214
+ name: 'comment',
219
215
  nodes: {
220
- [uuid-comment1] : {
221
- id: uuid-comment1,
216
+ [commentID1] : {
217
+ id: commentID1,
222
218
  state: {
223
- author : uuid-user2,
219
+ author : userID2,
224
220
  comment : ".....",
225
221
  }
226
222
  },
227
- [uuid-comment2] : {
228
- id : uuid-comment2,
223
+ [commentID2] : {
224
+ id : commentID2,
229
225
  state: {
230
- author : uuid-user3,
226
+ author : userID3,
231
227
  comment : ".....",
232
228
  }
233
229
  },
234
- [uuid-comment3] : {
235
- id : uuid-comment3,
230
+ [commentID3] : {
231
+ id : commentID3,
236
232
  state: {
237
- author : uuid-user3,
233
+ author : userID3,
238
234
  comment : ".....",
239
235
  }
240
236
  },
241
- [uuid-comment4] : {
242
- id : uuid-comment4,
237
+ [commentID4] : {
238
+ id : commentID4,
243
239
  state: {
244
- author : uuid-user1,
240
+ author : userID1,
245
241
  comment : ".....",
246
242
  }
247
243
  },
248
- [uuid-comment5] : {
249
- id : uuid-comment5,
244
+ [commentID5] : {
245
+ id : commentID5,
250
246
  state: {
251
- author : uuid-user3,
247
+ author : userID3,
252
248
  comment : ".....",
253
249
  }
254
250
  }
@@ -263,22 +259,22 @@ and:
263
259
  moduleStateUser = {
264
260
  name: 'user',
265
261
  nodes: {
266
- [uuid-user1] : {
267
- id: uuid-user1,
262
+ [userID1] : {
263
+ id: userID1,
268
264
  state: {
269
265
  username : "user1",
270
266
  name : "User 1",
271
267
  }
272
268
  },
273
- [uuid-user2] : {
274
- id: uuid-user2,
269
+ [userID2] : {
270
+ id: userID2,
275
271
  state: {
276
272
  username : "user2",
277
273
  name : "User 2",
278
274
  }
279
275
  },
280
- [uuid-user3] : {
281
- id: uuid-user3,
276
+ [userID3] : {
277
+ id: userID3,
282
278
  state: {
283
279
  username : "user3",
284
280
  name : "User 3",
@@ -292,52 +288,145 @@ moduleStateUser = {
292
288
 
293
289
  ## [APIs](https://github.com/chhsiao1981/use-thunk/blob/main/src/index.d.ts)
294
290
 
295
- ### Basic
291
+ #### Types
292
+
293
+ ##### `ThunkModule<S extends State>`
294
+
295
+ ```ts
296
+ export type ThunkModule<S extends State> = {
297
+ name: string
298
+ defaultState: S
299
+
300
+ // The rest of the variables are doModule.
301
+ // Specifying index-signatures to include all the variables.
302
+ [action: string]: ThunkFunc<S> | string | S
303
+ }
304
+ ```
305
+
306
+ A ThunkModule represents a self-contained domain state slice implemented within a single file. It encapsulates the module's identity, its initial data structure, and the business logic workflows (thunk functions) that act upon it.
307
+
308
+ ##### `ThunkFunc<S extends State>`
309
+
310
+ ```ts
311
+ export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>
312
+ ```
313
+
314
+ The thunk functions in a thunk module.
296
315
 
297
- ##### `createThunk(theModule: ThunkModule)`
316
+ ##### `Thunk`
298
317
 
299
- Create a module state for `theModule`.
318
+ `Thunk` is defined as:
319
+
320
+ ```ts
321
+ export type Thunk<S extends State> = async (
322
+ set: set<S>,
323
+ get: (id?: string) => S,
324
+ getOrNull: (id?: string) => S | null | undefined,
325
+ dispatch: dispatch<S>,
326
+ getModuleState: () => ModuleState<S>,
327
+ ) => void
328
+ ```
329
+
330
+ `Thunk`s can be async functions if needed (ex: `fetch` data).
331
+
332
+ We generally use only `set` and `get`.
333
+
334
+ * `set`: can be used in the following setting:
335
+ * `set(ThunkFunc())`: calling a thunk function.
336
+ * `set(id, data: Partial<S>)`: upsert state of `id` (syntax sugar of `set(upsert(id, data))`).
337
+ * `get`: (Guaranteed) get the state of `id` (or `defaultID` if `id` is not present).
338
+ * `getOrNull`: get the state of `id`. Get the state of `defaultID` if `id` is not present. Return `null` if `id` or state is not available.
339
+ * `dispatch`: `dispatch(ThunkFunc())` (calling a thunk function).
340
+ * `getModuleState`: get the whole module state.
341
+
342
+ ##### `doModule<S extends State>`
343
+
344
+ ```ts
345
+ export interface doModule<S extends State> {
346
+ [action: string]: ThunkFunc<S>
347
+ }
348
+ ```
349
+
350
+ ##### `toDoModule`
351
+
352
+ ```ts
353
+ export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'defaultState'>
354
+ ```
355
+
356
+ Converting `ThunkModule` to `doModule` by omitting `name` and `defaultState`.
357
+
358
+ #### RegisterThunk / ThunkContext / useThunk
359
+
360
+ ##### `registerThunk(module: ThunkModule)`
361
+
362
+ Register a thunk module.
300
363
 
301
364
  ##### `<ThunkContext>{children}</ThunkContext>`
302
365
 
303
- Rendering Thunk context.
366
+ Rendering thunk context.
304
367
 
305
368
  ##### `useThunk(theDo: ThunkModule): UseThunk`
306
369
 
307
- Similar to `React.useReducer`, but we use `useThunk`, and we also bind the actions with set (similar concept as `mapDispatchToProps`).
370
+ Similar to `React.useReducer`, but we use `useThunk`. In addition, we bind the thunk functions with `dispatch`, so we can directly use `do[Module].[function]()` (similar concept as `zustand`).
308
371
 
309
372
  return: `UseThunk`
310
373
 
311
- ### Default Thunk functions.
374
+ #### State
312
375
 
313
- ##### `init({myID, parentID, doParent, state}, myuuidv4?)`
376
+ ##### `getState(theUseThunk: UseThunk, id?: string): [state, doModule, theID]`
314
377
 
315
- initializing the state.
378
+ (Guaranteed) Get the state of `id` (or `defaultID` if `id` is not present) by `UseThunk`. If `defaultID` is not available, generate new ID as `defaultID`. If state is not available, clone `defaultState` as the state.
316
379
 
317
- ##### `update(myID, data)`
380
+ return: `[state, doModule, theID]`
318
381
 
319
- update the data to myID.
382
+ #### Misc
320
383
 
321
- ##### `remove(myID)`
384
+ ##### `genID(): string`
322
385
 
323
- remove the state.
386
+ Generate `id` for the state.
324
387
 
325
- ##### `genUUID(myuuidv4?: () => string): string`
388
+ ### Advanced Usage
326
389
 
327
- generate uuid for the state.
390
+ #### types
328
391
 
329
- ### State
392
+ ##### `UseThunk`
330
393
 
331
- ##### `getState(theUseThunk: UseThunk, myID?: string): [state, doModule, theID]`
394
+ ```ts
395
+ export type UseThunk<S extends State, R extends doModule<S>> = [Readonly<ModuleState<S>>, setMap<S, R>]
396
+ ```
332
397
 
333
- Get the state of `myID` by `UseThunk`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
398
+ ##### `setMap`
334
399
 
335
- return: `[state, doModule, theID]`
400
+ ```ts
401
+ export type setMap<S extends State, T extends doModule<S>> = {
402
+ [action in keyof T]: VoidReturnType<T[action]>
403
+ } & Omit<DefaultSetMap, keyof T>
404
+ ```
405
+
406
+ #### Primitive Thunk Functions.
407
+
408
+ ##### `init({id, parentID, doParent, state})`
409
+
410
+ Initialize the state.
411
+
412
+ ##### `update(id, data)`
413
+
414
+ Update the data to `id`.
415
+
416
+ ##### `upsert(id, data)`
417
+
418
+ Initialize the state with `defaultState` if it does not exist, and update the data to `id`.
419
+
420
+ ##### `remove(id)`
421
+
422
+ Remove the state.
423
+
424
+ #### State
336
425
 
337
- ##### `getStateOrNullByModule(moduleState: ModuleState, myID?: string): state | null`
426
+ ##### `getStateOrNullByModule(moduleState: ModuleState, id?: string): state | null`
338
427
 
339
- Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `null` if not available.
428
+ Get the state of `id`. Get the state of `defaultID` if `id` is not present. Return `null` if not available.
340
429
 
341
- ##### `getStateByModule(moduleState: ModuleState, myID?: string): state`
430
+ ##### `getStateByModule(moduleState: ModuleState, id?: string): state`
342
431
 
343
- Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
432
+ (Guaranteed) Get the state of `id` (or `defaultID` if `id` is not present) by module state. If `defaultID` is not available, generate new ID as `defaultID`. If state is not available, clone `defaultState` as the state.
@@ -1,4 +1,4 @@
1
- import type { State } from '../stateTypes';
1
+ import type { State } from '../states';
2
2
  import type BaseAction from './baseAction';
3
3
  import type { Thunk } from './thunk';
4
4
  export type ActionOrThunk<S extends State> = BaseAction | Thunk<S>;
@@ -1,8 +1,8 @@
1
- import type { ModuleState, State } from '../stateTypes';
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 GetModuleState<S extends State> = () => ModuleState<S>;
8
+ export type getModuleState<S extends State> = () => ModuleState<S>;
@@ -0,0 +1,5 @@
1
+ import type { dispatch } from '../dispatch';
2
+ import type { get, getOrNull } from '../get';
3
+ import type { set } from '../set';
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;
@@ -0,0 +1,10 @@
1
+ import { INIT, type InitParams, init, reduceInit } from './init';
2
+ export { INIT, type InitParams, init, reduceInit };
3
+ import { reduceUpdate, UPDATE, update } from './update';
4
+ export { reduceUpdate, UPDATE, update };
5
+ import { REMOVE, reduceRemove, remove } from './remove';
6
+ export { REMOVE, reduceRemove, remove };
7
+ import { reduceUpsert, UPSERT, upsert } from './upsert';
8
+ export { UPSERT, upsert, reduceUpsert };
9
+ import { reduceSetDefaultID, SET_DEFAULT_ID, setDefaultID } from './setDefaultID';
10
+ export { SET_DEFAULT_ID, setDefaultID, reduceSetDefaultID };
@@ -0,0 +1,9 @@
1
+ import type { Thunk } from '../../action';
2
+ import type { State } from '../../states';
3
+ import { INIT, reduceInit } from './initCore';
4
+ export { INIT, reduceInit };
5
+ export interface InitParams<S extends State> {
6
+ myID?: string;
7
+ state: S;
8
+ }
9
+ export declare const init: <S extends State>(params: InitParams<S>) => Thunk<S>;
@@ -1,5 +1,5 @@
1
- import type BaseAction from '../action/baseAction';
2
- import type { ModuleState, State } from '../stateTypes';
1
+ import type { BaseAction } from '../../action';
2
+ import type { ModuleState, State } from '../../states';
3
3
  export interface InitAction<S extends State> extends BaseAction {
4
4
  state: S;
5
5
  }
@@ -1,5 +1,5 @@
1
- import type BaseAction from './action/baseAction';
2
- import type { ModuleState, State } from './stateTypes';
1
+ import type { BaseAction } from '../action';
2
+ import type { ModuleState, State } from '../states';
3
3
  export declare const REMOVE = "@chhsiao1981/use-thunk/REMOVE";
4
4
  export declare const remove: (myID: string) => BaseAction;
5
5
  export declare const reduceRemove: <S extends State>(moduleState: ModuleState<S>, action: BaseAction) => ModuleState<S>;
@@ -1,5 +1,5 @@
1
- import type BaseAction from './action/baseAction';
2
- import type { ModuleState, State } from './stateTypes';
1
+ import type { BaseAction } from '../action';
2
+ import type { ModuleState, State } from '../states';
3
3
  export declare const SET_DEFAULT_ID = "@chhsiao1981/use-thunk/SET_DEFAULT_ID";
4
4
  export declare const setDefaultID: (myID: string) => BaseAction;
5
5
  export declare const reduceSetDefaultID: <S extends State>(moduleState: ModuleState<S>, action: BaseAction) => ModuleState<S>;
@@ -1,5 +1,5 @@
1
- import type BaseAction from './action/baseAction';
2
- import type { ModuleState, State } from './stateTypes';
1
+ import type { BaseAction } from '../action';
2
+ import type { ModuleState, State } from '../states';
3
3
  export declare const UPDATE = "@chhsiao1981/use-thunk/UPDATE";
4
4
  export declare const update: <S extends State>(myID: string, data: Partial<S>) => BaseAction;
5
5
  export declare const reduceUpdate: <S extends State>(moduleState: ModuleState<S>, action: BaseAction) => ModuleState<S>;
@@ -0,0 +1,5 @@
1
+ import type { BaseAction } from '../action';
2
+ import type { ModuleState, State } from '../states';
3
+ export declare const UPSERT = "@chhsiao1981/use-thunk/UPSERT";
4
+ export declare const upsert: <S extends State>(myID: string, data: Partial<S>) => BaseAction;
5
+ export declare const reduceUpsert: <S extends State>(moduleState: ModuleState<S>, action: BaseAction) => ModuleState<S>;
@@ -1,4 +1,4 @@
1
- import type { Dispatch as rDispatch } from 'react';
1
+ import type { Dispatch } from 'react';
2
2
  import type { ActionOrThunk } from './action';
3
- import type { State } from './stateTypes';
4
- export type Dispatch<S extends State> = rDispatch<ActionOrThunk<S>>;
3
+ import type { State } from './states';
4
+ export type dispatch<S extends State> = Dispatch<ActionOrThunk<S>>;
package/dist/get.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { State } from './states';
2
+ export type get<S extends State> = (id?: string) => S;
3
+ export type getOrNull<S extends State> = (id?: string) => S | null | undefined;
package/dist/index.d.ts CHANGED
@@ -1,15 +1,12 @@
1
- import type { GetClassState, Thunk } from './action';
2
- import createThunk, { registerThunk } from './createThunk';
3
- import type { Dispatch } from './dispatch';
4
- import type { DispatchFuncMap } from './dispatchFuncMap';
5
- import { genUUID } from './genUUID';
6
- import { type InitParams, init } from './init';
7
- import { remove } from './remove';
8
- import { setDefaultID } from './setDefaultID';
9
- import { getDefaultID, getNode, getState, mustGetState, mustGetStateByThunk } from './states';
10
- import type { ClassState, NodeState, NodeStateMap, State } from './stateTypes';
11
- import ThunkContext from './ThunkContext';
12
- import type { ThunkModule, ThunkModuleToFunc } from './thunk';
13
- import { setData, update } from './update';
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 { getDefaultID, getNodeOrNull, getState, getStateByModule, getStateOrNullByModule, type ModuleState, type State } from './states';
8
+ import { ThunkContext } from './thunkContext';
9
+ import type { doModule, ThunkModule, toDoModule } from './thunkModule';
14
10
  import useThunk, { type UseThunk } from './useThunk';
15
- export { createThunk, registerThunk, useThunk, ThunkContext, type UseThunk, type State, type NodeState, type NodeStateMap, type ClassState, type GetClassState, type Thunk, type ThunkModule, type ThunkModuleToFunc, type Dispatch, type DispatchFuncMap, getDefaultID, getNode, getState, mustGetState, mustGetStateByThunk, init, type InitParams, setData, update, remove, setDefaultID, genUUID, };
11
+ import { genID } from './utils';
12
+ export { type Thunk, type set, type get, type getOrNull, type dispatch, type getModuleState, registerThunk, useThunk, type UseThunk, ThunkContext, type State, getState, type ModuleState, type ThunkModule, type toDoModule, type doModule, type ThunkFunc, init, type InitParams, update, upsert, remove, genID, type setMap, setDefaultID, getNodeOrNull, getDefaultID, getStateOrNullByModule, getStateByModule, };