@chhsiao1981/use-thunk 13.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.
- package/README.md +109 -83
- package/dist/dispatch.d.ts +3 -3
- package/dist/index.d.ts +11 -14
- package/dist/index.js +173 -0
- package/dist/index.umd.cjs +1 -0
- package/dist/thunkContext/ThunkContext.d.ts +7 -0
- package/{types → dist}/thunkModule/index.d.ts +1 -1
- package/package.json +28 -17
- package/dist/ThunkContext.d.ts +0 -7
- package/dist/action.d.ts +0 -11
- package/dist/createReducer.d.ts +0 -4
- package/dist/createThunk.d.ts +0 -4
- package/dist/dispatchFuncMap.d.ts +0 -18
- package/dist/genUUID.d.ts +0 -1
- package/dist/init.d.ts +0 -16
- package/dist/reduceMap.d.ts +0 -6
- package/dist/reducer.d.ts +0 -5
- package/dist/remove.d.ts +0 -5
- package/dist/setDefaultID.d.ts +0 -5
- package/dist/stateTypes.d.ts +0 -16
- package/dist/states.d.ts +0 -9
- package/dist/thunk.d.ts +0 -15
- package/dist/thunkContextMap.d.ts +0 -15
- package/dist/thunkContextTypes.d.ts +0 -8
- package/dist/thunkModuleFuncMap.d.ts +0 -7
- package/dist/update.d.ts +0 -6
- package/dist/useThunk.d.ts +0 -12
- package/dist/useThunkReducer.d.ts +0 -17
- package/src/action/ActionOrThunk.ts +0 -5
- package/src/action/baseAction.ts +0 -6
- package/src/action/index.ts +0 -16
- package/src/action/thunk.ts +0 -13
- package/src/defaultThunks/index.ts +0 -15
- package/src/defaultThunks/init/index.ts +0 -27
- package/src/defaultThunks/init/initCore.ts +0 -31
- package/src/defaultThunks/remove.ts +0 -35
- package/src/defaultThunks/setDefaultID.ts +0 -18
- package/src/defaultThunks/update.ts +0 -26
- package/src/defaultThunks/upsert.ts +0 -27
- package/src/dispatch.ts +0 -7
- package/src/get.ts +0 -4
- package/src/index.ts +0 -58
- package/src/reducer/createReducer.ts +0 -18
- package/src/reducer/defaultReduceMap.ts +0 -26
- package/src/reducer/index.ts +0 -12
- package/src/reducer/reduceMap.ts +0 -6
- package/src/registerThunk.ts +0 -29
- package/src/set/index.ts +0 -9
- package/src/set/setMap.ts +0 -59
- package/src/states/index.ts +0 -84
- package/src/states/types.ts +0 -23
- package/src/thunkContext/ThunkContext.tsx +0 -46
- package/src/thunkContext/index.ts +0 -9
- package/src/thunkContext/thunkContextMap.ts +0 -22
- package/src/thunkContext/types.ts +0 -8
- package/src/thunkModule/defaultDoModule.ts +0 -13
- package/src/thunkModule/index.ts +0 -21
- package/src/useThunk/index.ts +0 -48
- package/src/useThunk/useThunkReducer.ts +0 -100
- package/src/utils/deepCopy.ts +0 -30
- package/src/utils/genID.ts +0 -6
- package/src/utils/index.ts +0 -3
- package/types/dispatch.d.ts +0 -4
- package/types/index.d.ts +0 -12
- package/types/thunkContext/ThunkContext.d.ts +0 -7
- /package/{types → dist}/action/ActionOrThunk.d.ts +0 -0
- /package/{types → dist}/action/baseAction.d.ts +0 -0
- /package/{types → dist}/action/index.d.ts +0 -0
- /package/{types → dist}/action/thunk.d.ts +0 -0
- /package/{types → dist}/defaultThunks/index.d.ts +0 -0
- /package/{types → dist}/defaultThunks/init/index.d.ts +0 -0
- /package/{types → dist}/defaultThunks/init/initCore.d.ts +0 -0
- /package/{types → dist}/defaultThunks/remove.d.ts +0 -0
- /package/{types → dist}/defaultThunks/setDefaultID.d.ts +0 -0
- /package/{types → dist}/defaultThunks/update.d.ts +0 -0
- /package/{types → dist}/defaultThunks/upsert.d.ts +0 -0
- /package/{types → dist}/get.d.ts +0 -0
- /package/{types → dist}/reducer/createReducer.d.ts +0 -0
- /package/{types → dist}/reducer/defaultReduceMap.d.ts +0 -0
- /package/{types → dist}/reducer/index.d.ts +0 -0
- /package/{types → dist}/reducer/reduceMap.d.ts +0 -0
- /package/{types → dist}/registerThunk.d.ts +0 -0
- /package/{types → dist}/set/index.d.ts +0 -0
- /package/{types → dist}/set/setMap.d.ts +0 -0
- /package/{types → dist}/states/index.d.ts +0 -0
- /package/{types → dist}/states/types.d.ts +0 -0
- /package/{types → dist}/thunkContext/index.d.ts +0 -0
- /package/{types → dist}/thunkContext/thunkContextMap.d.ts +0 -0
- /package/{types → dist}/thunkContext/types.d.ts +0 -0
- /package/{types → dist}/thunkModule/defaultDoModule.d.ts +0 -0
- /package/{types → dist}/useThunk/index.d.ts +0 -0
- /package/{types → dist}/useThunk/useThunkReducer.d.ts +0 -0
- /package/{types → dist}/utils/deepCopy.d.ts +0 -0
- /package/{types → dist}/utils/genID.d.ts +0 -0
- /package/{types → dist}/utils/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ For usage examples, please refer to [demo-use-thunk](https://github.com/chhsiao1
|
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
|
-
npm install
|
|
17
|
+
npm install @chhsiao1981/use-thunk
|
|
18
18
|
|
|
19
19
|
## Getting Started
|
|
20
20
|
|
|
@@ -104,10 +104,6 @@ createRoot(document.getElementById("root")!).render(
|
|
|
104
104
|
)
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
## Introduction
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
107
|
## Development Pattern
|
|
112
108
|
### Must Included in a Thunk Module
|
|
113
109
|
|
|
@@ -165,14 +161,23 @@ createRoot(document.getElementById("root")!).render(
|
|
|
165
161
|
)
|
|
166
162
|
```
|
|
167
163
|
|
|
168
|
-
##
|
|
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
|
|
169
175
|
|
|
170
|
-
The general concept of normalized state can be found in [Normalizing State Shape](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape)
|
|
171
|
-
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:
|
|
172
177
|
|
|
173
|
-
1.
|
|
174
|
-
2. NodeState: the state of a node, including the id of the node and the
|
|
175
|
-
3. State: the
|
|
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.
|
|
176
181
|
|
|
177
182
|
For example, the example [in the redux link](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape) is represented as:
|
|
178
183
|
|
|
@@ -180,24 +185,24 @@ For example, the example [in the redux link](https://redux.js.org/recipes/struct
|
|
|
180
185
|
moduleStatePost = {
|
|
181
186
|
name: 'post',
|
|
182
187
|
nodes: {
|
|
183
|
-
[
|
|
184
|
-
id:
|
|
188
|
+
[postID1] : {
|
|
189
|
+
id: postID1,
|
|
185
190
|
state: {
|
|
186
|
-
author :
|
|
191
|
+
author : userID1,
|
|
187
192
|
body : "......",
|
|
188
|
-
comments: [
|
|
193
|
+
comments: [commentID1, commentID2]
|
|
189
194
|
},
|
|
190
195
|
},
|
|
191
|
-
[
|
|
192
|
-
id :
|
|
196
|
+
[postID2] : {
|
|
197
|
+
id : postID2,
|
|
193
198
|
state: {
|
|
194
|
-
author :
|
|
199
|
+
author : userID2,
|
|
195
200
|
body : "......",
|
|
196
|
-
comments: [
|
|
201
|
+
comments: [commentID3, commentID4, commentID5]
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
},
|
|
200
|
-
defaultID,
|
|
205
|
+
defaultID,
|
|
201
206
|
defaultState,
|
|
202
207
|
}
|
|
203
208
|
```
|
|
@@ -206,40 +211,40 @@ and:
|
|
|
206
211
|
|
|
207
212
|
```ts
|
|
208
213
|
moduleStateComment = {
|
|
209
|
-
|
|
214
|
+
name: 'comment',
|
|
210
215
|
nodes: {
|
|
211
|
-
[
|
|
212
|
-
id:
|
|
216
|
+
[commentID1] : {
|
|
217
|
+
id: commentID1,
|
|
213
218
|
state: {
|
|
214
|
-
author :
|
|
219
|
+
author : userID2,
|
|
215
220
|
comment : ".....",
|
|
216
221
|
}
|
|
217
222
|
},
|
|
218
|
-
[
|
|
219
|
-
id :
|
|
223
|
+
[commentID2] : {
|
|
224
|
+
id : commentID2,
|
|
220
225
|
state: {
|
|
221
|
-
author :
|
|
226
|
+
author : userID3,
|
|
222
227
|
comment : ".....",
|
|
223
228
|
}
|
|
224
229
|
},
|
|
225
|
-
[
|
|
226
|
-
id :
|
|
230
|
+
[commentID3] : {
|
|
231
|
+
id : commentID3,
|
|
227
232
|
state: {
|
|
228
|
-
author :
|
|
233
|
+
author : userID3,
|
|
229
234
|
comment : ".....",
|
|
230
235
|
}
|
|
231
236
|
},
|
|
232
|
-
[
|
|
233
|
-
id :
|
|
237
|
+
[commentID4] : {
|
|
238
|
+
id : commentID4,
|
|
234
239
|
state: {
|
|
235
|
-
author :
|
|
240
|
+
author : userID1,
|
|
236
241
|
comment : ".....",
|
|
237
242
|
}
|
|
238
243
|
},
|
|
239
|
-
[
|
|
240
|
-
id :
|
|
244
|
+
[commentID5] : {
|
|
245
|
+
id : commentID5,
|
|
241
246
|
state: {
|
|
242
|
-
author :
|
|
247
|
+
author : userID3,
|
|
243
248
|
comment : ".....",
|
|
244
249
|
}
|
|
245
250
|
}
|
|
@@ -254,22 +259,22 @@ and:
|
|
|
254
259
|
moduleStateUser = {
|
|
255
260
|
name: 'user',
|
|
256
261
|
nodes: {
|
|
257
|
-
[
|
|
258
|
-
id:
|
|
262
|
+
[userID1] : {
|
|
263
|
+
id: userID1,
|
|
259
264
|
state: {
|
|
260
265
|
username : "user1",
|
|
261
266
|
name : "User 1",
|
|
262
267
|
}
|
|
263
268
|
},
|
|
264
|
-
[
|
|
265
|
-
id:
|
|
269
|
+
[userID2] : {
|
|
270
|
+
id: userID2,
|
|
266
271
|
state: {
|
|
267
272
|
username : "user2",
|
|
268
273
|
name : "User 2",
|
|
269
274
|
}
|
|
270
275
|
},
|
|
271
|
-
[
|
|
272
|
-
id:
|
|
276
|
+
[userID3] : {
|
|
277
|
+
id: userID3,
|
|
273
278
|
state: {
|
|
274
279
|
username : "user3",
|
|
275
280
|
name : "User 3",
|
|
@@ -285,12 +290,35 @@ moduleStateUser = {
|
|
|
285
290
|
|
|
286
291
|
#### Types
|
|
287
292
|
|
|
288
|
-
##### `
|
|
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.
|
|
315
|
+
|
|
316
|
+
##### `Thunk`
|
|
289
317
|
|
|
290
318
|
`Thunk` is defined as:
|
|
291
319
|
|
|
292
320
|
```ts
|
|
293
|
-
export type Thunk<S extends State> = (
|
|
321
|
+
export type Thunk<S extends State> = async (
|
|
294
322
|
set: set<S>,
|
|
295
323
|
get: (id?: string) => S,
|
|
296
324
|
getOrNull: (id?: string) => S | null | undefined,
|
|
@@ -299,20 +327,17 @@ export type Thunk<S extends State> = (
|
|
|
299
327
|
) => void
|
|
300
328
|
```
|
|
301
329
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
##### `ThunkModule<S extends State>`
|
|
330
|
+
`Thunk`s can be async functions if needed (ex: `fetch` data).
|
|
305
331
|
|
|
306
|
-
|
|
307
|
-
export type ThunkModule<S extends State> = {
|
|
308
|
-
name: string
|
|
309
|
-
defaultState: S
|
|
332
|
+
We generally use only `set` and `get`.
|
|
310
333
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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.
|
|
316
341
|
|
|
317
342
|
##### `doModule<S extends State>`
|
|
318
343
|
|
|
@@ -322,17 +347,19 @@ export interface doModule<S extends State> {
|
|
|
322
347
|
}
|
|
323
348
|
```
|
|
324
349
|
|
|
325
|
-
##### `
|
|
350
|
+
##### `toDoModule`
|
|
326
351
|
|
|
327
352
|
```ts
|
|
328
|
-
export type
|
|
353
|
+
export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'defaultState'>
|
|
329
354
|
```
|
|
330
355
|
|
|
356
|
+
Converting `ThunkModule` to `doModule` by omitting `name` and `defaultState`.
|
|
357
|
+
|
|
331
358
|
#### RegisterThunk / ThunkContext / useThunk
|
|
332
359
|
|
|
333
360
|
##### `registerThunk(module: ThunkModule)`
|
|
334
361
|
|
|
335
|
-
|
|
362
|
+
Register a thunk module.
|
|
336
363
|
|
|
337
364
|
##### `<ThunkContext>{children}</ThunkContext>`
|
|
338
365
|
|
|
@@ -340,18 +367,24 @@ Rendering thunk context.
|
|
|
340
367
|
|
|
341
368
|
##### `useThunk(theDo: ThunkModule): UseThunk`
|
|
342
369
|
|
|
343
|
-
Similar to `React.useReducer`, but we use `useThunk
|
|
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`).
|
|
344
371
|
|
|
345
372
|
return: `UseThunk`
|
|
346
373
|
|
|
347
374
|
#### State
|
|
348
375
|
|
|
349
|
-
##### `getState(theUseThunk: UseThunk,
|
|
376
|
+
##### `getState(theUseThunk: UseThunk, id?: string): [state, doModule, theID]`
|
|
350
377
|
|
|
351
|
-
Get the state of `
|
|
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.
|
|
352
379
|
|
|
353
380
|
return: `[state, doModule, theID]`
|
|
354
|
-
|
|
381
|
+
|
|
382
|
+
#### Misc
|
|
383
|
+
|
|
384
|
+
##### `genID(): string`
|
|
385
|
+
|
|
386
|
+
Generate `id` for the state.
|
|
387
|
+
|
|
355
388
|
### Advanced Usage
|
|
356
389
|
|
|
357
390
|
#### types
|
|
@@ -370,37 +403,30 @@ export type setMap<S extends State, T extends doModule<S>> = {
|
|
|
370
403
|
} & Omit<DefaultSetMap, keyof T>
|
|
371
404
|
```
|
|
372
405
|
|
|
373
|
-
####
|
|
406
|
+
#### Primitive Thunk Functions.
|
|
374
407
|
|
|
375
|
-
##### `init({
|
|
408
|
+
##### `init({id, parentID, doParent, state})`
|
|
376
409
|
|
|
377
|
-
|
|
410
|
+
Initialize the state.
|
|
378
411
|
|
|
379
|
-
##### `update(
|
|
412
|
+
##### `update(id, data)`
|
|
380
413
|
|
|
381
|
-
|
|
414
|
+
Update the data to `id`.
|
|
382
415
|
|
|
383
|
-
##### `upsert(
|
|
416
|
+
##### `upsert(id, data)`
|
|
384
417
|
|
|
385
|
-
|
|
418
|
+
Initialize the state with `defaultState` if it does not exist, and update the data to `id`.
|
|
386
419
|
|
|
387
|
-
##### `remove(
|
|
420
|
+
##### `remove(id)`
|
|
388
421
|
|
|
389
|
-
|
|
422
|
+
Remove the state.
|
|
390
423
|
|
|
391
424
|
#### State
|
|
392
425
|
|
|
393
|
-
##### `getStateOrNullByModule(moduleState: ModuleState,
|
|
394
|
-
|
|
395
|
-
Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `null` if not available.
|
|
396
|
-
|
|
397
|
-
##### `getStateByModule(moduleState: ModuleState, myID?: string): state`
|
|
398
|
-
|
|
399
|
-
Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
|
|
426
|
+
##### `getStateOrNullByModule(moduleState: ModuleState, id?: string): state | null`
|
|
400
427
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
##### `genID(): string`
|
|
428
|
+
Get the state of `id`. Get the state of `defaultID` if `id` is not present. Return `null` if not available.
|
|
404
429
|
|
|
405
|
-
|
|
430
|
+
##### `getStateByModule(moduleState: ModuleState, id?: string): state`
|
|
406
431
|
|
|
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.
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Dispatch
|
|
1
|
+
import type { Dispatch } from 'react';
|
|
2
2
|
import type { ActionOrThunk } from './action';
|
|
3
|
-
import type { State } from './
|
|
4
|
-
export type
|
|
3
|
+
import type { State } from './states';
|
|
4
|
+
export type dispatch<S extends State> = Dispatch<ActionOrThunk<S>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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
|
-
|
|
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, };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { createContext as e, useCallback as t, useContext as n, useMemo as r, useState as i } from "react";
|
|
2
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
3
|
+
//#region src/utils/deepCopy.ts
|
|
4
|
+
var o = (e) => {
|
|
5
|
+
if (typeof e != "object" || !e) return e;
|
|
6
|
+
if (e instanceof Date) return new Date(e.getTime());
|
|
7
|
+
if (Array.isArray(e)) return e.map((e) => o(e));
|
|
8
|
+
let t = {};
|
|
9
|
+
for (let n in e) e.hasOwnProperty(n) && (t[n] = o(e[n]));
|
|
10
|
+
return t;
|
|
11
|
+
}, s = 1, c = () => (s += 1, `${s}`), l = "@chhsiao1981/use-thunk/SET_DEFAULT_ID", u = (e) => ({
|
|
12
|
+
myID: e,
|
|
13
|
+
type: l
|
|
14
|
+
}), d = (e, t) => {
|
|
15
|
+
let { myID: n } = t;
|
|
16
|
+
return Object.assign({}, e, {
|
|
17
|
+
defaultID: n,
|
|
18
|
+
isInitDefaultID: !0
|
|
19
|
+
});
|
|
20
|
+
}, f = "@chhsiao1981/use-thunk/INIT", p = (e, t) => ({
|
|
21
|
+
myID: e,
|
|
22
|
+
type: f,
|
|
23
|
+
state: t
|
|
24
|
+
}), m = (e, t) => {
|
|
25
|
+
let { myID: n, state: r } = t, i = {
|
|
26
|
+
id: n,
|
|
27
|
+
state: r
|
|
28
|
+
}, a = Object.assign({}, e.nodes, { [n]: i });
|
|
29
|
+
return Object.assign({}, e, { nodes: a });
|
|
30
|
+
}, h = (e) => (t, n, r, i, a) => {
|
|
31
|
+
let o = e.myID ?? c(), { state: s } = e;
|
|
32
|
+
t(p(o, s));
|
|
33
|
+
let { defaultID: l } = a();
|
|
34
|
+
l || t(u(o));
|
|
35
|
+
}, g = "@chhsiao1981/use-thunk/UPDATE", _ = (e, t) => ({
|
|
36
|
+
myID: e,
|
|
37
|
+
type: g,
|
|
38
|
+
data: t
|
|
39
|
+
}), v = (e, t) => {
|
|
40
|
+
let { myID: n, data: r } = t, i = e.nodes[n];
|
|
41
|
+
if (!i) return e;
|
|
42
|
+
let a = Object.assign({}, i.state, r), o = Object.assign({}, i, { state: a }), s = Object.assign({}, e.nodes, { [n]: o });
|
|
43
|
+
return Object.assign({}, e, { nodes: s });
|
|
44
|
+
}, y = "@chhsiao1981/use-thunk/REMOVE", b = (e) => ({
|
|
45
|
+
myID: e,
|
|
46
|
+
type: y
|
|
47
|
+
}), x = (e, t) => {
|
|
48
|
+
let { myID: n } = t;
|
|
49
|
+
if (!e.nodes[n]) return e;
|
|
50
|
+
let r = Object.keys(e.nodes).filter((e) => e !== n).reduce((t, n) => (t[n] = e.nodes[n], t), {}), i = Object.assign({}, e, { nodes: r });
|
|
51
|
+
return i.defaultID === n && (i.defaultID = null), i;
|
|
52
|
+
}, S = "@chhsiao1981/use-thunk/UPSERT", C = (e, t) => ({
|
|
53
|
+
myID: e,
|
|
54
|
+
type: S,
|
|
55
|
+
data: t
|
|
56
|
+
}), w = (e, t) => {
|
|
57
|
+
let { myID: n, data: r } = t, i = e.nodes[n] ?? {
|
|
58
|
+
id: n,
|
|
59
|
+
state: o(e.defaultState)
|
|
60
|
+
}, a = Object.assign({}, i.state, r), s = Object.assign({}, i, { state: a }), c = Object.assign({}, e.nodes, { [n]: s });
|
|
61
|
+
return Object.assign({}, e, { nodes: c });
|
|
62
|
+
}, T = {
|
|
63
|
+
theMap: {},
|
|
64
|
+
theList: []
|
|
65
|
+
}, E = (e) => {
|
|
66
|
+
let { modules: t, children: n } = e, o = t || T.theList;
|
|
67
|
+
if (o.length === 0) return n;
|
|
68
|
+
let s = o[0], { context: c, refModuleState: l } = T.theMap[s], [u, d] = i(l.current);
|
|
69
|
+
l.current = u;
|
|
70
|
+
let f = r(() => ({
|
|
71
|
+
refModuleState: l,
|
|
72
|
+
setModuleState: d
|
|
73
|
+
}), [u]), p = o.length === 1 ? n : E({
|
|
74
|
+
modules: o.slice(1),
|
|
75
|
+
children: n
|
|
76
|
+
});
|
|
77
|
+
return /* @__PURE__ */ a(c.Provider, {
|
|
78
|
+
value: f,
|
|
79
|
+
children: p
|
|
80
|
+
});
|
|
81
|
+
}, D = (t) => {
|
|
82
|
+
let { name: n, defaultState: r } = t;
|
|
83
|
+
if (T.theMap[n]) {
|
|
84
|
+
console.warn("registerThunk: already init:", n);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
let i = {
|
|
88
|
+
name: n,
|
|
89
|
+
nodes: {},
|
|
90
|
+
defaultState: r
|
|
91
|
+
}, a = () => {}, o = { current: i }, s = e({
|
|
92
|
+
refModuleState: o,
|
|
93
|
+
setModuleState: a
|
|
94
|
+
});
|
|
95
|
+
T.theMap[n] = {
|
|
96
|
+
context: s,
|
|
97
|
+
refModuleState: o
|
|
98
|
+
}, T.theList = Object.keys(T.theMap).sort(), console.info("registerThunk: done:", n);
|
|
99
|
+
}, O = (e) => e.defaultID ?? "", k = (e, t) => {
|
|
100
|
+
let n = t || O(e);
|
|
101
|
+
return n && e.nodes[n] || null;
|
|
102
|
+
}, A = (e, t) => {
|
|
103
|
+
let n = t || O(e);
|
|
104
|
+
if (!n) return null;
|
|
105
|
+
let r = e.nodes[n];
|
|
106
|
+
return r ? r.state : null;
|
|
107
|
+
}, j = (e, t) => {
|
|
108
|
+
let n = t || O(e) || c(), r = A(e, n);
|
|
109
|
+
if (r) return r;
|
|
110
|
+
let i = o(e.defaultState), a = {
|
|
111
|
+
id: n,
|
|
112
|
+
state: i
|
|
113
|
+
};
|
|
114
|
+
return e.nodes[n] = a, e.isInitDefaultID || e.defaultID || (e.defaultID = n, e.isInitDefaultID = !0), i;
|
|
115
|
+
}, M = (e, t) => {
|
|
116
|
+
let [n, r] = e, i = t || O(n);
|
|
117
|
+
return [
|
|
118
|
+
j(n, i),
|
|
119
|
+
r,
|
|
120
|
+
i
|
|
121
|
+
];
|
|
122
|
+
}, N = {
|
|
123
|
+
[f]: m,
|
|
124
|
+
[g]: v,
|
|
125
|
+
[y]: x,
|
|
126
|
+
[S]: w,
|
|
127
|
+
[l]: d
|
|
128
|
+
}, P = () => (e, t) => t && N[t.type] ? N[t.type](e, t) : e, F = {
|
|
129
|
+
init: h,
|
|
130
|
+
update: _,
|
|
131
|
+
remove: b
|
|
132
|
+
}, I = (e, t, n) => (Object.keys(e).filter((t) => typeof e[t] == "function").reduce((n, r) => {
|
|
133
|
+
if (n[r]) return n;
|
|
134
|
+
let i = e[r];
|
|
135
|
+
return n[r] = (...e) => t(i(...e)), n;
|
|
136
|
+
}, n), Object.keys(F).reduce((e, n) => {
|
|
137
|
+
if (e[n]) return e;
|
|
138
|
+
let r = F[n];
|
|
139
|
+
return e[n] = (...e) => t(r(...e)), e;
|
|
140
|
+
}, n), n), L = (e, r) => {
|
|
141
|
+
let { context: i } = T.theMap[r], { refModuleState: a, setModuleState: o } = n(i), s = t(() => a.current, [a]), c = t((e) => {
|
|
142
|
+
a.current = e, o(e);
|
|
143
|
+
}, [a, o]), l = t((e) => A(s(), e), [s]), u = t((e) => j(s(), e), [s]), d = t((t) => e(s(), t), [e, s]), f = t((e) => {
|
|
144
|
+
if (typeof e == "function") {
|
|
145
|
+
e(p, u, l, f, s);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
c(d(e));
|
|
149
|
+
}, [
|
|
150
|
+
s,
|
|
151
|
+
c,
|
|
152
|
+
d
|
|
153
|
+
]), p = t((e, t) => {
|
|
154
|
+
if (typeof e == "string") {
|
|
155
|
+
if (!t) return;
|
|
156
|
+
c(d(C(e, t)));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
f(e);
|
|
160
|
+
}, [
|
|
161
|
+
s,
|
|
162
|
+
c,
|
|
163
|
+
d
|
|
164
|
+
]);
|
|
165
|
+
return [a.current, p];
|
|
166
|
+
}, R = {}, z = (e) => {
|
|
167
|
+
let { name: t } = e, n = !R[t];
|
|
168
|
+
n && (R[t] = {});
|
|
169
|
+
let i = R[t], [a, o] = L(r(() => P(), []), t), s = r(() => [a, i], [a, i]);
|
|
170
|
+
return n && I(e, o, i), s;
|
|
171
|
+
};
|
|
172
|
+
//#endregion
|
|
173
|
+
export { E as ThunkContext, c as genID, O as getDefaultID, k as getNodeOrNull, M as getState, j as getStateByModule, A as getStateOrNullByModule, h as init, D as registerThunk, b as remove, u as setDefaultID, _ as update, C as upsert, z as useThunk };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e[`@chhsiao1981/use-thunk`]={},e.React,e.ReactJSXRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=e=>{if(typeof e!=`object`||!e)return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(e=>r(e));let t={};for(let n in e)e.hasOwnProperty(n)&&(t[n]=r(e[n]));return t},i=1,a=()=>(i+=1,`${i}`),o=`@chhsiao1981/use-thunk/SET_DEFAULT_ID`,s=e=>({myID:e,type:o}),c=(e,t)=>{let{myID:n}=t;return Object.assign({},e,{defaultID:n,isInitDefaultID:!0})},l=`@chhsiao1981/use-thunk/INIT`,u=(e,t)=>({myID:e,type:l,state:t}),d=(e,t)=>{let{myID:n,state:r}=t,i={id:n,state:r},a=Object.assign({},e.nodes,{[n]:i});return Object.assign({},e,{nodes:a})},f=e=>(t,n,r,i,o)=>{let c=e.myID??a(),{state:l}=e;t(u(c,l));let{defaultID:d}=o();d||t(s(c))},p=`@chhsiao1981/use-thunk/UPDATE`,m=(e,t)=>({myID:e,type:p,data:t}),h=(e,t)=>{let{myID:n,data:r}=t,i=e.nodes[n];if(!i)return e;let a=Object.assign({},i.state,r),o=Object.assign({},i,{state:a}),s=Object.assign({},e.nodes,{[n]:o});return Object.assign({},e,{nodes:s})},g=`@chhsiao1981/use-thunk/REMOVE`,_=e=>({myID:e,type:g}),v=(e,t)=>{let{myID:n}=t;if(!e.nodes[n])return e;let r=Object.keys(e.nodes).filter(e=>e!==n).reduce((t,n)=>(t[n]=e.nodes[n],t),{}),i=Object.assign({},e,{nodes:r});return i.defaultID===n&&(i.defaultID=null),i},y=`@chhsiao1981/use-thunk/UPSERT`,b=(e,t)=>({myID:e,type:y,data:t}),x=(e,t)=>{let{myID:n,data:i}=t,a=e.nodes[n]??{id:n,state:r(e.defaultState)},o=Object.assign({},a.state,i),s=Object.assign({},a,{state:o}),c=Object.assign({},e.nodes,{[n]:s});return Object.assign({},e,{nodes:c})},S={theMap:{},theList:[]},C=e=>{let{modules:r,children:i}=e,a=r||S.theList;if(a.length===0)return i;let o=a[0],{context:s,refModuleState:c}=S.theMap[o],[l,u]=(0,t.useState)(c.current);c.current=l;let d=(0,t.useMemo)(()=>({refModuleState:c,setModuleState:u}),[l]),f=a.length===1?i:C({modules:a.slice(1),children:i});return(0,n.jsx)(s.Provider,{value:d,children:f})},w=e=>{let{name:n,defaultState:r}=e;if(S.theMap[n]){console.warn(`registerThunk: already init:`,n);return}let i={name:n,nodes:{},defaultState:r},a=()=>{},o={current:i},s=(0,t.createContext)({refModuleState:o,setModuleState:a});S.theMap[n]={context:s,refModuleState:o},S.theList=Object.keys(S.theMap).sort(),console.info(`registerThunk: done:`,n)},T=e=>e.defaultID??``,E=(e,t)=>{let n=t||T(e);return n&&e.nodes[n]||null},D=(e,t)=>{let n=t||T(e);if(!n)return null;let r=e.nodes[n];return r?r.state:null},O=(e,t)=>{let n=t||T(e)||a(),i=D(e,n);if(i)return i;let o=r(e.defaultState),s={id:n,state:o};return e.nodes[n]=s,e.isInitDefaultID||e.defaultID||(e.defaultID=n,e.isInitDefaultID=!0),o},k=(e,t)=>{let[n,r]=e,i=t||T(n);return[O(n,i),r,i]},A={[l]:d,[p]:h,[g]:v,[y]:x,[o]:c},j=()=>(e,t)=>t&&A[t.type]?A[t.type](e,t):e,M={init:f,update:m,remove:_},N=(e,t,n)=>(Object.keys(e).filter(t=>typeof e[t]==`function`).reduce((n,r)=>{if(n[r])return n;let i=e[r];return n[r]=(...e)=>t(i(...e)),n},n),Object.keys(M).reduce((e,n)=>{if(e[n])return e;let r=M[n];return e[n]=(...e)=>t(r(...e)),e},n),n),P=(e,n)=>{let{context:r}=S.theMap[n],{refModuleState:i,setModuleState:a}=(0,t.useContext)(r),o=(0,t.useCallback)(()=>i.current,[i]),s=(0,t.useCallback)(e=>{i.current=e,a(e)},[i,a]),c=(0,t.useCallback)(e=>D(o(),e),[o]),l=(0,t.useCallback)(e=>O(o(),e),[o]),u=(0,t.useCallback)(t=>e(o(),t),[e,o]),d=(0,t.useCallback)(e=>{if(typeof e==`function`){e(f,l,c,d,o);return}s(u(e))},[o,s,u]),f=(0,t.useCallback)((e,t)=>{if(typeof e==`string`){if(!t)return;s(u(b(e,t)));return}d(e)},[o,s,u]);return[i.current,f]},F={};e.ThunkContext=C,e.genID=a,e.getDefaultID=T,e.getNodeOrNull=E,e.getState=k,e.getStateByModule=O,e.getStateOrNullByModule=D,e.init=f,e.registerThunk=w,e.remove=_,e.setDefaultID=s,e.update=m,e.upsert=b,e.useThunk=e=>{let{name:n}=e,r=!F[n];r&&(F[n]={});let i=F[n],[a,o]=P((0,t.useMemo)(()=>j(),[]),n),s=(0,t.useMemo)(()=>[a,i],[a,i]);return r&&N(e,o,i),s}});
|
|
@@ -10,4 +10,4 @@ export type ThunkModule<S extends State> = {
|
|
|
10
10
|
defaultState: S;
|
|
11
11
|
[action: string]: ThunkFunc<S> | string | S;
|
|
12
12
|
};
|
|
13
|
-
export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | '
|
|
13
|
+
export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'defaultState'>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chhsiao1981/use-thunk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.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",
|
|
@@ -8,12 +8,19 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/chhsiao1981/use-thunk"
|
|
10
10
|
},
|
|
11
|
-
"main": "
|
|
12
|
-
"
|
|
11
|
+
"main": "dist/index.umd.cjs",
|
|
12
|
+
"module": "dist/index.js",
|
|
13
|
+
"types": "dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.umd.cjs",
|
|
19
|
+
"default": "./dist/index.umd.cjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
13
22
|
"files": [
|
|
14
|
-
"
|
|
15
|
-
"dist",
|
|
16
|
-
"types"
|
|
23
|
+
"dist"
|
|
17
24
|
],
|
|
18
25
|
"author": {
|
|
19
26
|
"name": "Chuan-Heng Hsiao",
|
|
@@ -24,34 +31,38 @@
|
|
|
24
31
|
"useThunk"
|
|
25
32
|
],
|
|
26
33
|
"scripts": {
|
|
27
|
-
"clean:lib": "rimraf ./dist/* ./types/*",
|
|
28
34
|
"compile:lib": "vite build",
|
|
29
|
-
"
|
|
30
|
-
"build": "npm run
|
|
35
|
+
"compile:types": "tsc -b",
|
|
36
|
+
"build": "npm run compile:lib && npm run compile:types",
|
|
37
|
+
|
|
31
38
|
"lint": "biome lint --error-on-warnings",
|
|
32
39
|
"test": "vitest run",
|
|
33
|
-
"
|
|
34
|
-
"coverage": "vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml",
|
|
35
|
-
"tsd": "npx -p typescript tsc src/*.ts --declaration --allowJs --emitDeclarationOnly --strict --jsx react-jsx --outDir types"
|
|
40
|
+
"coverage": "vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml"
|
|
36
41
|
},
|
|
37
42
|
"license": "MIT",
|
|
38
43
|
"devDependencies": {
|
|
39
|
-
"@
|
|
44
|
+
"@babel/core": "^7.29.0",
|
|
45
|
+
"@biomejs/biome": "^2.5.1",
|
|
46
|
+
"@rolldown/plugin-babel": "^0.2.3",
|
|
47
|
+
"@types/babel__core": "^7.20.5",
|
|
40
48
|
"@types/node": "^25.9.3",
|
|
41
|
-
"@types/react": ">=18.3.1",
|
|
42
49
|
"@types/react-dom": ">=18.3.1",
|
|
43
|
-
"@vitejs/plugin-react
|
|
50
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
44
51
|
"@vitest/coverage-v8": "^4.1.8",
|
|
52
|
+
"babel-plugin-react-compiler": "^1.0.0",
|
|
45
53
|
"globals": "^17.6.0",
|
|
46
54
|
"happy-dom": "^20.10.2",
|
|
47
55
|
"jiti": "^2.7.0",
|
|
48
56
|
"react-dom": ">=18.3.1",
|
|
49
|
-
"rimraf": "^6.1.3",
|
|
50
57
|
"typescript": "~5.9.3",
|
|
51
|
-
"vite": "^
|
|
58
|
+
"vite": "^8.0.16",
|
|
52
59
|
"vitest": "^4.1.8"
|
|
53
60
|
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"react-compiler-runtime": "^1.0.0"
|
|
63
|
+
},
|
|
54
64
|
"peerDependencies": {
|
|
65
|
+
"@types/react": ">=18.3.1",
|
|
55
66
|
"react": ">=18.3.1"
|
|
56
67
|
}
|
|
57
68
|
}
|