Skip to content

Commit 12fce12

Browse files
committed
refactor(model): refactor actions
(state, actions, params) => (params, { state, actions }) re #85, re #83
1 parent 0b0aedf commit 12fce12

File tree

8 files changed

+104
-15
lines changed

8 files changed

+104
-15
lines changed

.npmignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ coverage/
2929
.rts2_cache_umd/
3030

3131
# Github
32-
.github/
32+
.github/
33+
.git/

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ npm install react-model
8181
- [FAQ](#faq)
8282
- [How can I disable the console debugger?](#how-can-i-disable-the-console-debugger)
8383
- [How can I add custom middleware](#how-can-i-add-custom-middleware)
84+
- [How can I make persist models](#how-can-i-make-persist-models)
8485

8586
## Core Concept
8687

@@ -655,3 +656,21 @@ export default Model(stores)
655656
```
656657
657658
[⇧ back to top](#table-of-contents)
659+
660+
#### How can I make persist models
661+
662+
```typescript
663+
import { actionMiddlewares, Model } from 'react-model'
664+
import Example from 'models/example'
665+
666+
const persistMiddleware: Middleware = async (context, restMiddlewares) => {
667+
localStorage.setItem('__REACT_MODEL__', JSON.stringify(context.Global.State))
668+
await context.next(restMiddlewares)
669+
}
670+
671+
actionMiddlewares.push(persistMiddleware)
672+
673+
Model({ Example }, JSON.parse(localStorage.getItem('__REACT_MODEL__')))
674+
```
675+
676+
[⇧ back to top](#table-of-contents)

__test__/Model/mixed.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/// <reference path="../index.d.ts" />
22
import { testHook } from 'react-hooks-testing-library'
3-
import { Counter } from '..'
3+
import { NextCounter } from '..'
44
import { Model } from '../../src'
55

66
describe('useStore', () => {
77
test('create by single model definition', async () => {
88
let state: any
99
let actions: any
1010
let count = 0
11-
const Home = Model(Counter)
11+
const Home = Model(NextCounter)
1212
const { useStore, subscribe, unsubscribe } = Model({ Home })
1313
testHook(() => {
1414
;[state, actions] = useStore('Home')

__test__/Model/single.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/// <reference path="../index.d.ts" />
22
import { testHook } from 'react-hooks-testing-library'
3-
import { Counter } from '..'
3+
import { NextCounter } from '..'
44
import { Model } from '../../src'
55

66
describe('useStore', () => {
77
test('create by single model definition', async () => {
88
let state: any
99
let actions: any
1010
let count = 0
11-
const { useStore, subscribe, unsubscribe } = Model(Counter)
11+
const { useStore, subscribe, unsubscribe } = Model(NextCounter)
1212
testHook(() => {
1313
;[state, actions] = useStore()
1414
})

__test__/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,26 @@ export const Counter: ModelType<
4545
}
4646
}
4747

48+
// v3.0
49+
export const NextCounter: NextModelType<
50+
CounterState,
51+
CounterActionParams & ExtraActionParams
52+
> = {
53+
state: { count: 0 },
54+
actions: {
55+
increment: params => {
56+
return state => {
57+
state.count += params
58+
}
59+
},
60+
add: (params, { state }) => {
61+
return {
62+
count: state.count + params
63+
}
64+
}
65+
}
66+
}
67+
4868
export const Theme: ModelType<ThemeState, ThemeActionParams> = {
4969
state: {
5070
theme: 'dark'

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-model",
3-
"version": "2.6.0",
3+
"version": "2.7.0",
44
"description": "The State management library for React",
55
"main": "./dist/react-model.js",
66
"umd:main": "./dist/react-model.umd.js",

src/index.d.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,32 @@ type Action<S = {}, P = any, ActionKeys = {}> = (
4747
| void
4848
| Promise<void>
4949

50+
// v3.0 Action
51+
type NextAction<S = {}, P = any, ActionKeys = {}> = (
52+
params: P,
53+
context: {
54+
state: S
55+
actions: getConsumerNextActionsType<NextActions<S, ActionKeys>>
56+
}
57+
) =>
58+
| Partial<S>
59+
| Promise<Partial<S>>
60+
| ProduceFunc<S>
61+
| Promise<ProduceFunc<S>>
62+
| void
63+
| Promise<void>
64+
5065
type ProduceFunc<S> = (state: S) => void
5166

5267
type Actions<S = {}, ActionKeys = {}> = {
5368
[P in keyof ActionKeys]: Action<S, ActionKeys[P], ActionKeys>
5469
}
5570

71+
// v3.0 Actions
72+
type NextActions<S = {}, ActionKeys = {}> = {
73+
[P in keyof ActionKeys]: NextAction<S, ActionKeys[P], ActionKeys>
74+
}
75+
5676
type Dispatch<A> = (value: A) => void
5777
type SetStateAction<S> = S | ((prevState: S) => S)
5878

@@ -90,14 +110,14 @@ type Middleware<S = {}> = (C: Context<S>, M: Middleware<S>[]) => void
90110
interface Models<State = any, ActionKeys = any> {
91111
[name: string]:
92112
| ModelType<State, ActionKeys>
93-
| API<ModelType<State, ActionKeys>>
113+
| API<NextModelType<State, ActionKeys>>
94114
}
95115

96-
interface API<MT extends ModelType = any> {
116+
interface API<MT extends NextModelType = any> {
97117
__id: string
98118
useStore: (
99119
depActions?: Array<keyof MT['actions']>
100-
) => [Get<MT, 'state'>, getConsumerActionsType<Get<MT, 'actions'>>]
120+
) => [Get<MT, 'state'>, getConsumerNextActionsType<Get<MT, 'actions'>>]
101121
getState: () => Readonly<Get<MT, 'state'>>
102122
subscribe: (
103123
actionName: keyof MT['actions'] | Array<keyof MT['actions']>,
@@ -106,7 +126,7 @@ interface API<MT extends ModelType = any> {
106126
unsubscribe: (
107127
actionName: keyof Get<MT, 'actions'> | Array<keyof Get<MT, 'actions'>>
108128
) => void
109-
actions: Readonly<getConsumerActionsType<Get<MT, 'actions'>>>
129+
actions: Readonly<getConsumerNextActionsType<Get<MT, 'actions'>>>
110130
}
111131

112132
interface APIs<M extends Models> {
@@ -158,6 +178,19 @@ type ModelType<InitStateType = any, ActionKeys = any> = {
158178
asyncState?: (context?: any) => Promise<Partial<InitStateType>>
159179
}
160180

181+
// v3.0
182+
type NextModelType<InitStateType = any, ActionKeys = any> = {
183+
actions: {
184+
[P in keyof ActionKeys]: NextAction<
185+
InitStateType,
186+
ActionKeys[P],
187+
ActionKeys
188+
>
189+
}
190+
state: InitStateType
191+
asyncState?: (context?: any) => Promise<Partial<InitStateType>>
192+
}
193+
161194
type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any
162195
? A
163196
: never
@@ -174,6 +207,13 @@ type getConsumerActionsType<A extends Actions<any, any>> = {
174207
) => ReturnType<A[P]>
175208
}
176209

210+
// v3.0
211+
type getConsumerNextActionsType<A extends NextActions<any, any>> = {
212+
[P in keyof A]: ArgumentTypes<A[P]>[0] extends undefined
213+
? (params?: ArgumentTypes<A[P]>[0]) => ReturnType<A[P]>
214+
: (params: ArgumentTypes<A[P]>[0]) => ReturnType<A[P]>
215+
}
216+
177217
type Get<Object, K extends keyof Object> = Object[K]
178218

179219
type ModelsProps<M extends Models> = {

src/index.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,36 @@ import {
1010
} from './helper'
1111
import { actionMiddlewares, applyMiddlewares, middlewares } from './middlewares'
1212

13-
const isModelType = (input: any): input is ModelType => {
13+
const isNextModelType = (input: any): input is NextModelType => {
1414
return (input as ModelType).state !== undefined
1515
}
1616

1717
const isAPI = (input: any): input is API => {
1818
return (input as API).useStore !== undefined
1919
}
2020

21-
function Model<MT extends ModelType>(models: MT): API<MT>
21+
function Model<MT extends NextModelType>(models: MT): API<MT>
2222
function Model<M extends Models>(
2323
models: M,
2424
initialState?: Global['State']
2525
): APIs<M>
26-
function Model<M extends Models, MT extends ModelType>(
26+
function Model<M extends Models, MT extends NextModelType>(
2727
models: M | MT,
2828
initialState?: Global['State']
2929
) {
30-
if (isModelType(models)) {
30+
if (isNextModelType(models)) {
3131
const hash = '__' + Global.uid
3232
Global.State[hash] = models.state
33-
Global.Actions[hash] = models.actions
33+
const nextActions: Actions = Object.entries(models.actions).reduce(
34+
(o: { [name: string]: Action }, [name, action]) => {
35+
o[name] = async (state, actions, params) => {
36+
return await action(params, { state, actions })
37+
}
38+
return o
39+
},
40+
{}
41+
)
42+
Global.Actions[hash] = nextActions
3443
Global.AsyncState[hash] = models.asyncState
3544
const actions = getActions(hash)
3645
return {

0 commit comments

Comments
 (0)