@chhsiao1981/use-thunk 11.0.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -99
- package/package.json +10 -16
- package/src/action/ActionOrThunk.ts +1 -1
- package/src/action/index.ts +3 -3
- package/src/action/thunk.ts +10 -2
- package/src/defaultThunks/index.ts +15 -0
- package/src/defaultThunks/init/index.ts +27 -0
- package/src/{init → defaultThunks/init}/initCore.ts +2 -2
- package/src/{remove.ts → defaultThunks/remove.ts} +2 -2
- package/src/{setDefaultID.ts → defaultThunks/setDefaultID.ts} +4 -3
- package/src/{update.ts → defaultThunks/update.ts} +2 -7
- package/src/defaultThunks/upsert.ts +27 -0
- package/src/dispatch.ts +7 -0
- package/src/get.ts +4 -0
- package/src/index.ts +43 -31
- package/src/reducer/createReducer.ts +18 -0
- package/src/reducer/defaultReduceMap.ts +26 -0
- package/src/{reducer.ts → reducer/index.ts} +5 -2
- package/src/reducer/reduceMap.ts +6 -0
- package/src/{createThunk.ts → registerThunk.ts} +11 -13
- package/src/set/index.ts +9 -0
- package/src/{setMap.ts → set/setMap.ts} +12 -18
- package/src/states/index.ts +84 -0
- package/src/{stateTypes.ts → states/types.ts} +7 -7
- package/src/thunkContext/index.ts +9 -0
- package/src/{thunkContextMap.ts → thunkContext/thunkContextMap.ts} +2 -2
- package/src/{thunkContextTypes.ts → thunkContext/types.ts} +1 -1
- package/src/thunkModule/defaultDoModule.ts +13 -0
- package/src/thunkModule/index.ts +12 -12
- package/src/{useThunk.ts → useThunk/index.ts} +7 -10
- package/src/{useThunkReducer.ts → useThunk/useThunkReducer.ts} +50 -10
- package/src/utils/deepCopy.ts +30 -0
- package/src/utils/genID.ts +6 -0
- package/src/utils/index.ts +3 -0
- package/types/action/ActionOrThunk.d.ts +1 -1
- package/types/action/index.d.ts +2 -2
- package/types/action/thunk.d.ts +4 -2
- package/types/defaultThunks/index.d.ts +10 -0
- package/types/defaultThunks/init/index.d.ts +9 -0
- package/types/{init → defaultThunks/init}/initCore.d.ts +2 -2
- package/types/{remove.d.ts → defaultThunks/remove.d.ts} +2 -2
- package/types/{setDefaultID.d.ts → defaultThunks/setDefaultID.d.ts} +2 -2
- package/types/{update.d.ts → defaultThunks/update.d.ts} +2 -3
- package/types/defaultThunks/upsert.d.ts +5 -0
- package/types/dispatch.d.ts +4 -4
- package/types/get.d.ts +3 -0
- package/types/index.d.ts +11 -20
- package/types/reducer/createReducer.d.ts +3 -0
- package/types/reducer/defaultReduceMap.d.ts +2 -0
- package/types/{reducer.d.ts → reducer/index.d.ts} +4 -2
- package/types/reducer/reduceMap.d.ts +5 -0
- package/types/{createThunk.d.ts → registerThunk.d.ts} +1 -2
- package/types/set/index.d.ts +5 -0
- package/types/set/setMap.d.ts +16 -0
- package/types/states/index.d.ts +10 -0
- package/types/{stateTypes.d.ts → states/types.d.ts} +6 -6
- package/types/thunkContext/index.d.ts +6 -0
- package/types/{thunkContextMap.d.ts → thunkContext/thunkContextMap.d.ts} +2 -2
- package/types/{thunkContextTypes.d.ts → thunkContext/types.d.ts} +1 -1
- package/types/thunkModule/defaultDoModule.d.ts +5 -0
- package/types/thunkModule/index.d.ts +8 -11
- package/types/useThunk/index.d.ts +9 -0
- package/types/{useThunkReducer.d.ts → useThunk/useThunkReducer.d.ts} +3 -3
- package/types/utils/deepCopy.d.ts +2 -0
- package/types/utils/genID.d.ts +1 -0
- package/types/utils/index.d.ts +3 -0
- package/src/createReducer.ts +0 -24
- package/src/genUUID.ts +0 -38
- package/src/init/index.ts +0 -26
- package/src/reduceMap.ts +0 -22
- package/src/set.ts +0 -7
- package/src/states.ts +0 -47
- package/src/thunkModule/defaultThunkModuleFuncMap.ts +0 -16
- package/types/createReducer.d.ts +0 -4
- package/types/dispatchFuncMap.d.ts +0 -17
- package/types/genUUID.d.ts +0 -1
- package/types/init/index.d.ts +0 -7
- package/types/reduceMap.d.ts +0 -6
- package/types/set.d.ts +0 -4
- package/types/setMap.d.ts +0 -17
- package/types/states.d.ts +0 -9
- package/types/thunkModule/defaultThunkModuleFuncMap.d.ts +0 -5
- package/types/useThunk.d.ts +0 -9
- /package/src/{ThunkContext.tsx → thunkContext/ThunkContext.tsx} +0 -0
- /package/types/{ThunkContext.d.ts → thunkContext/ThunkContext.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -2,39 +2,28 @@
|
|
|
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 `10.0.0`: The ClassState is shared globally, with `registerThunk` and `ThunkContext`.
|
|
23
|
-
* Starting from `9.0.0`: npm package is renamed as [@chhsiao1981/use-thunk](https://www.npmjs.com/package/%40chhsiao1981/use-thunk)
|
|
24
|
-
* Starting from `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).
|
|
25
14
|
|
|
26
15
|
## Install
|
|
27
16
|
|
|
28
17
|
npm install --save @chhsiao1981/use-thunk
|
|
29
18
|
|
|
30
|
-
##
|
|
19
|
+
## Getting Started
|
|
31
20
|
|
|
32
|
-
Thunk module able to do increment (
|
|
21
|
+
Thunk module able to do increment (thunks/increment.ts):
|
|
33
22
|
|
|
34
23
|
```ts
|
|
35
|
-
import {
|
|
24
|
+
import { type Thunk, type State as rState, update } from '@chhsiao1981/use-thunk'
|
|
36
25
|
|
|
37
|
-
export const
|
|
26
|
+
export const name = 'demo/Increment'
|
|
38
27
|
|
|
39
28
|
export interface State extends rState {
|
|
40
29
|
count: number
|
|
@@ -44,54 +33,53 @@ export const defaultState: State = {
|
|
|
44
33
|
count: 0
|
|
45
34
|
}
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return async (
|
|
50
|
-
|
|
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 })
|
|
51
43
|
}
|
|
52
44
|
}
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let me =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
46
|
+
// or we can treat set as dispatching a base action.
|
|
47
|
+
export const increment2 = (myID: string): Thunk<State> => {
|
|
48
|
+
return async (set, get) => {
|
|
49
|
+
let me = get(myID)
|
|
50
|
+
const {count} = me
|
|
51
|
+
|
|
52
|
+
set(update({ count: count + 2 }))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
61
55
|
|
|
62
|
-
|
|
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))
|
|
63
60
|
}
|
|
64
61
|
}
|
|
65
62
|
```
|
|
66
63
|
|
|
67
|
-
App.tsx:
|
|
64
|
+
components/App.tsx:
|
|
68
65
|
|
|
69
66
|
```tsx
|
|
70
|
-
import { type ThunkModuleToFunc, useThunk,
|
|
71
|
-
import * as DoIncrement from './
|
|
72
|
-
|
|
73
|
-
type TDoIncrement = ThunkModuleToFunc(typeof DoIncrement)
|
|
74
|
-
|
|
75
|
-
type Props = {
|
|
76
|
-
}
|
|
67
|
+
import { type ThunkModuleToFunc, useThunk, getState } from '@chhsiao1981/use-thunk'
|
|
68
|
+
import * as DoIncrement from './thunks/increment'
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
const [classStateIncrement, doIncrement] = useThunk<DoIncrement.State, TDoIncrement>(DoIncrement, StateType.LOCAL)
|
|
70
|
+
type doIncrement = toDoModule(typeof DoIncrement)
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}, [])
|
|
85
|
-
|
|
86
|
-
// states
|
|
87
|
-
const incrementID = getDefaultID(classStateIncrement)
|
|
88
|
-
const increment = getState(classStateIncrement) || DoIncrement.defaultState
|
|
72
|
+
export default () => {
|
|
73
|
+
const useIncrement = useThunk<DoIncrement.State, doIncrement>(DoIncrement)
|
|
74
|
+
const [increment, doIncrement, incrementID] = getState(useIncrement)
|
|
89
75
|
|
|
90
76
|
// to render
|
|
91
77
|
return (
|
|
92
78
|
<div>
|
|
93
79
|
<p>count: {increment.count}</p>
|
|
94
|
-
<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>
|
|
95
83
|
</div>
|
|
96
84
|
)
|
|
97
85
|
}
|
|
@@ -102,8 +90,8 @@ main.tsx:
|
|
|
102
90
|
import { registerThunk, ThunkContext } from "@chhsiao1981/use-thunk";
|
|
103
91
|
import { StrictMode } from "react";
|
|
104
92
|
import { createRoot } from "react-dom/client";
|
|
105
|
-
import * as DoIncrement from './
|
|
106
|
-
import App from "./App
|
|
93
|
+
import * as DoIncrement from './thunks/increment'
|
|
94
|
+
import App from "./components/App";
|
|
107
95
|
|
|
108
96
|
registerThunk(DoIncrement)
|
|
109
97
|
|
|
@@ -116,47 +104,54 @@ createRoot(document.getElementById("root")!).render(
|
|
|
116
104
|
)
|
|
117
105
|
```
|
|
118
106
|
|
|
107
|
+
## Introduction
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## Development Pattern
|
|
119
112
|
### Must Included in a Thunk Module
|
|
120
113
|
|
|
121
114
|
```ts
|
|
122
115
|
import type { State as rState } from '@chhsiao1981/use-thunk'
|
|
123
116
|
|
|
124
|
-
//
|
|
125
|
-
export const
|
|
117
|
+
// Thunk-module name.
|
|
118
|
+
export const name = ""
|
|
126
119
|
|
|
127
120
|
// state definition of the reducer.
|
|
128
121
|
export interface State extends rState {
|
|
129
122
|
}
|
|
130
123
|
|
|
124
|
+
export const defaultState: State = {}
|
|
125
|
+
|
|
131
126
|
.
|
|
132
127
|
.
|
|
133
128
|
.
|
|
134
129
|
```
|
|
135
130
|
|
|
136
|
-
### Must Included in a
|
|
131
|
+
### Must Included in a Statically-allocated (always allocated) Component
|
|
137
132
|
|
|
138
133
|
```ts
|
|
139
|
-
import { type
|
|
140
|
-
import * as DoModule from '../
|
|
134
|
+
import { type toDoModule, useThunk, getState } from '@chhsiao1981/use-thunk'
|
|
135
|
+
import * as DoModule from '../thunks/module'
|
|
141
136
|
|
|
142
|
-
type
|
|
137
|
+
type doModule = toDoModule<typeof DoModule>
|
|
143
138
|
|
|
144
139
|
const Component = () => {
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
const moduleID = getDefaultID(stateModule)
|
|
148
|
-
const theModule = getState(stateModule)
|
|
140
|
+
const useModule = useThunk<DoModule.State, doModule>(DoModule)
|
|
141
|
+
const [module, doModule, moduleID] = getState(useModule)
|
|
149
142
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
143
|
+
.
|
|
144
|
+
.
|
|
145
|
+
.
|
|
153
146
|
}
|
|
154
147
|
```
|
|
155
148
|
|
|
156
|
-
### Must Included in main.tsx
|
|
149
|
+
### Must Included in `main.tsx`
|
|
157
150
|
|
|
158
151
|
```tsx
|
|
159
|
-
registerThunk
|
|
152
|
+
import { registerThunk, ThunkContext } from '@chhsiao1981/use-thunk'
|
|
153
|
+
import * as DoModule from '../thunks/module'
|
|
154
|
+
registerThunk(DoModule)
|
|
160
155
|
.
|
|
161
156
|
.
|
|
162
157
|
.
|
|
@@ -182,8 +177,8 @@ with the following features:
|
|
|
182
177
|
For example, the example [in the redux link](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape) is represented as:
|
|
183
178
|
|
|
184
179
|
```ts
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
moduleStatePost = {
|
|
181
|
+
name: 'post',
|
|
187
182
|
nodes: {
|
|
188
183
|
[uuid-post1] : {
|
|
189
184
|
id: uuid-post1,
|
|
@@ -202,7 +197,7 @@ classStatePost = {
|
|
|
202
197
|
}
|
|
203
198
|
}
|
|
204
199
|
},
|
|
205
|
-
defaultID,
|
|
200
|
+
defaultID,s
|
|
206
201
|
defaultState,
|
|
207
202
|
}
|
|
208
203
|
```
|
|
@@ -210,8 +205,8 @@ classStatePost = {
|
|
|
210
205
|
and:
|
|
211
206
|
|
|
212
207
|
```ts
|
|
213
|
-
|
|
214
|
-
myClass: '
|
|
208
|
+
moduleStateComment = {
|
|
209
|
+
myClass: 'module',
|
|
215
210
|
nodes: {
|
|
216
211
|
[uuid-comment1] : {
|
|
217
212
|
id: uuid-comment1,
|
|
@@ -256,8 +251,8 @@ classStateComment = {
|
|
|
256
251
|
|
|
257
252
|
and:
|
|
258
253
|
```ts
|
|
259
|
-
|
|
260
|
-
|
|
254
|
+
moduleStateUser = {
|
|
255
|
+
name: 'user',
|
|
261
256
|
nodes: {
|
|
262
257
|
[uuid-user1] : {
|
|
263
258
|
id: uuid-user1,
|
|
@@ -288,52 +283,124 @@ classStateUser = {
|
|
|
288
283
|
|
|
289
284
|
## [APIs](https://github.com/chhsiao1981/use-thunk/blob/main/src/index.d.ts)
|
|
290
285
|
|
|
291
|
-
|
|
286
|
+
#### Types
|
|
292
287
|
|
|
293
|
-
##### `
|
|
288
|
+
##### `type Thunk`
|
|
294
289
|
|
|
295
|
-
|
|
290
|
+
`Thunk` is defined as:
|
|
296
291
|
|
|
297
|
-
|
|
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
|
+
```
|
|
301
|
+
|
|
302
|
+
We generally use only `set` and `get`.
|
|
303
|
+
|
|
304
|
+
##### `ThunkModule<S extends State>`
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
export type ThunkModule<S extends State> = {
|
|
308
|
+
name: string
|
|
309
|
+
defaultState: S
|
|
310
|
+
|
|
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
|
+
```
|
|
298
316
|
|
|
299
|
-
##### `
|
|
317
|
+
##### `doModule<S extends State>`
|
|
300
318
|
|
|
301
|
-
|
|
319
|
+
```ts
|
|
320
|
+
export interface doModule<S extends State> {
|
|
321
|
+
[action: string]: ThunkFunc<S>
|
|
322
|
+
}
|
|
323
|
+
```
|
|
302
324
|
|
|
303
|
-
##### `
|
|
325
|
+
##### `ThunkFunc<S extends State>`
|
|
304
326
|
|
|
305
|
-
|
|
327
|
+
```ts
|
|
328
|
+
export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>
|
|
329
|
+
```
|
|
306
330
|
|
|
307
|
-
|
|
331
|
+
#### RegisterThunk / ThunkContext / useThunk
|
|
308
332
|
|
|
309
|
-
|
|
333
|
+
##### `registerThunk(module: ThunkModule)`
|
|
310
334
|
|
|
311
|
-
|
|
335
|
+
register a thunk module.
|
|
312
336
|
|
|
313
|
-
|
|
337
|
+
##### `<ThunkContext>{children}</ThunkContext>`
|
|
314
338
|
|
|
315
|
-
|
|
339
|
+
Rendering thunk context.
|
|
316
340
|
|
|
317
|
-
##### `
|
|
341
|
+
##### `useThunk(theDo: ThunkModule): UseThunk`
|
|
318
342
|
|
|
319
|
-
|
|
343
|
+
Similar to `React.useReducer`, but we use `useThunk`, and we also bind the actions with `set` (similar concept as `mapDispatchToProps`).
|
|
320
344
|
|
|
321
|
-
|
|
345
|
+
return: `UseThunk`
|
|
322
346
|
|
|
323
|
-
|
|
347
|
+
#### State
|
|
324
348
|
|
|
325
|
-
##### `
|
|
349
|
+
##### `getState(theUseThunk: UseThunk, myID?: string): [state, doModule, theID]`
|
|
326
350
|
|
|
327
351
|
Get the state of `myID` by `UseThunk`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
|
|
328
352
|
|
|
329
|
-
return: `[
|
|
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
|
+
```
|
|
330
372
|
|
|
331
|
-
|
|
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
|
|
392
|
+
|
|
393
|
+
##### `getStateOrNullByModule(moduleState: ModuleState, myID?: string): state | null`
|
|
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.
|
|
332
400
|
|
|
333
|
-
|
|
401
|
+
#### Misc
|
|
334
402
|
|
|
335
|
-
|
|
403
|
+
##### `genID(): string`
|
|
336
404
|
|
|
337
|
-
|
|
405
|
+
generate id for the state.
|
|
338
406
|
|
|
339
|
-
Get the node of `myID`. Get the node of `defaultID` if `myID` is not present.
|
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,5 +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
|
-
export type Thunk<S extends State> = (
|
|
7
|
+
export type Thunk<S extends State> = (
|
|
8
|
+
set: set<S>,
|
|
9
|
+
get: get<S>,
|
|
10
|
+
getOrNull: getOrNull<S>,
|
|
11
|
+
dispatch: dispatch<S>,
|
|
12
|
+
getModuleState: () => ModuleState<S>,
|
|
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 => ({
|
|
@@ -8,11 +8,6 @@ export const update = <S extends State>(myID: string, data: Partial<S>): BaseAct
|
|
|
8
8
|
data,
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
export const setData = <S extends State>(myID: string, data: Partial<S>): BaseAction => {
|
|
12
|
-
console.warn('setData will be deprecated in the next version.')
|
|
13
|
-
return update(myID, data)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
export const reduceUpdate = <S extends State>(
|
|
17
12
|
moduleState: ModuleState<S>,
|
|
18
13
|
action: 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
ADDED