Skip to content

Commit 9468d2b

Browse files
Merge branch 'master' into greenkeeper/immer-3.0.0
2 parents ec502fb + b4639a9 commit 9468d2b

File tree

10 files changed

+193
-202
lines changed

10 files changed

+193
-202
lines changed

README.md

Lines changed: 40 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const Todo = {
2727
// s is the readonly version of state
2828
// you can also return partial state here but don't need to keep immutable manually
2929
// state is the mutable state
30-
return state => state.items.push(todo)
30+
return state => {
31+
state.items.push(todo)
32+
}
3133
}
3234
}
3335
}
@@ -56,6 +58,8 @@ const TodoList = () => {
5658

5759
[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)
5860

61+
[v2 docs](https://github.com/byte-fe/react-model/blob/v2/README.md)
62+
5963
install package
6064

6165
```shell
@@ -83,84 +87,15 @@ npm install react-model
8387
- [How can I add custom middleware](#how-can-i-add-custom-middleware)
8488
- [How can I make persist models](#how-can-i-make-persist-models)
8589
- [How can I deal with local state](#how-can-i-deal-with-local-state)
86-
- [actions throw error from immer.module.js](#actions-throw-error-from-immer.module.js)
90+
- [actions throw error from immer.module.js](#actions-throw-error-from-immermodulejs)
91+
- [How can I customize each model's middlewares?](#how-can-i-customize-each-models-middlewares)
8792

8893
## Core Concept
8994

9095
### Model
9196

9297
Every model have their own state and actions.
9398

94-
<details>
95-
<summary><del>old model</del> (will be deprecated in v3.0)</summary>
96-
<p>
97-
98-
```typescript
99-
const initialState = {
100-
counter: 0,
101-
light: false,
102-
response: {}
103-
}
104-
105-
interface StateType = {
106-
counter: number
107-
light: boolean
108-
response: {
109-
code?: number
110-
message?: string
111-
}
112-
}
113-
114-
interface ActionsParamType = {
115-
increment: number
116-
openLight: undefined
117-
get: undefined
118-
} // You only need to tag the type of params here !
119-
120-
const model: ModelType<StateType, ActionsParamType> = {
121-
actions: {
122-
increment: async (state, _, params) => {
123-
return {
124-
counter: state.counter + (params || 1)
125-
}
126-
},
127-
openLight: async (state, actions) => {
128-
await actions.increment(1) // You can use other actions within the model
129-
await actions.get() // support async functions (block actions)
130-
actions.get()
131-
await actions.increment(1) // + 1
132-
await actions.increment(1) // + 2
133-
await actions.increment(1) // + 3 as expected !
134-
return { light: !state.light }
135-
},
136-
get: async () => {
137-
await new Promise((resolve, reject) =>
138-
setTimeout(() => {
139-
resolve()
140-
}, 3000)
141-
)
142-
return {
143-
response: {
144-
code: 200,
145-
message: `${new Date().toLocaleString()} open light success`
146-
}
147-
}
148-
}
149-
},
150-
state: initialState
151-
}
152-
153-
export default model
154-
155-
// You can use these types when use Class Components.
156-
// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>
157-
// type ConsumerType = { actions: ConsumerActionsType; state: StateType }
158-
// type ActionType = ConsumerActionsType
159-
// export { ConsumerType, StateType, ActionType }
160-
```
161-
</p>
162-
</details>
163-
16499
```typescript
165100
const initialState = {
166101
counter: 0,
@@ -850,4 +785,36 @@ actions: {
850785
}
851786
```
852787
853-
[⇧ back to top](#table-of-contents)
788+
[⇧ back to top](#table-of-contents)
789+
790+
### How can I customize each model's middlewares?
791+
792+
If you are using NextModel, you can customize each model's middlewares.
793+
794+
```typescript
795+
import { actionMiddlewares, Model } from 'react-model'
796+
import { delayMiddleware } from './middlewares'
797+
798+
const nextCounterModel: NextModelType<CounterState, NextCounterActionParams> = {
799+
actions: {
800+
add: num => {
801+
return state => {
802+
state.count += num
803+
}
804+
},
805+
increment: async (num, { actions }) => {
806+
actions.add(num)
807+
await timeout(300, {})
808+
}
809+
},
810+
// You can define the custom middlewares here
811+
middlewares: [delayMiddleware, ...actionMiddlewares],
812+
state: {
813+
count: 0
814+
}
815+
}
816+
817+
export default Model(nextCounterModel)
818+
```
819+
820+
[⇧ back to top](#table-of-contents)

__test__/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ type CounterActionParams = {
1515
increment: number
1616
}
1717

18+
type NextCounterActionParams = {
19+
increment: number
20+
add: number
21+
}
22+
1823
type ExtraActionParams = {
1924
add: number
2025
}

__test__/index.ts

Lines changed: 73 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
/// <reference path="./index.d.ts" />
22
/// <reference path="../src/index.d.ts" />
3+
import { Model } from '../src'
34
import { timeout } from '../src/helper'
5+
import { actionMiddlewares } from '../src/middlewares'
46

57
export const ActionsTester: ModelType<ActionTesterState, ActionTesterParams> = {
6-
state: {
7-
response: {
8-
data: {}
9-
},
10-
data: {}
11-
},
128
actions: {
139
get: async () => {
1410
const response = await timeout(9, { code: 0, data: { counter: 1000 } })
1511
return { response }
1612
},
13+
getData: async (_, { actions }) => {
14+
await actions.get()
15+
actions.parse()
16+
},
1717
parse: () => {
1818
return state => {
1919
state.data = state.response.data
2020
}
21-
},
22-
getData: async (_, actions) => {
23-
await actions.get()
24-
actions.parse()
21+
}
22+
},
23+
state: {
24+
data: {},
25+
response: {
26+
data: {}
2527
}
2628
}
2729
}
@@ -30,97 +32,122 @@ export const Counter: ModelType<
3032
CounterState,
3133
CounterActionParams & ExtraActionParams
3234
> = {
33-
state: { count: 0 },
3435
actions: {
35-
increment: (_, __, params) => {
36-
return state => {
37-
state.count += params
38-
}
39-
},
40-
add: (state, __, params) => {
36+
add: (params, { state }) => {
4137
return {
4238
count: state.count + params
4339
}
40+
},
41+
increment: params => {
42+
return state => {
43+
state.count += params
44+
}
4445
}
45-
}
46+
},
47+
state: { count: 0 }
4648
}
4749

4850
// v3.0
49-
export const NextCounter: NextModelType<
51+
export const NextCounter: ModelType<
5052
CounterState,
5153
CounterActionParams & ExtraActionParams
5254
> = {
53-
state: { count: 0 },
5455
actions: {
55-
increment: params => {
56-
return state => {
57-
state.count += params
58-
}
59-
},
6056
add: (params, { state }) => {
6157
return {
6258
count: state.count + params
6359
}
60+
},
61+
increment: params => {
62+
return state => {
63+
state.count += params
64+
}
6465
}
65-
}
66+
},
67+
state: { count: 0 }
6668
}
6769

6870
export const Theme: ModelType<ThemeState, ThemeActionParams> = {
69-
state: {
70-
theme: 'dark'
71-
},
7271
actions: {
73-
changeTheme: state => ({
72+
changeTheme: (_, { state }) => ({
7473
theme: state.theme === 'dark' ? 'light' : 'dark'
7574
})
75+
},
76+
state: {
77+
theme: 'dark'
7678
}
7779
}
7880

7981
export const AsyncCounter: ModelType<CounterState, CounterActionParams> = {
80-
state: { count: 0 },
81-
asyncState: async (context: { count?: number }) => ({
82-
count: context ? context.count || 1 : 1
83-
}),
8482
actions: {
85-
increment: (_, __, params) => {
83+
increment: params => {
8684
return state => {
8785
state.count += params
8886
}
8987
}
90-
}
88+
},
89+
asyncState: async (context: { count?: number }) => ({
90+
count: context ? context.count || 1 : 1
91+
}),
92+
state: { count: 0 }
9193
}
9294

9395
export const AsyncNull: ModelType<CounterState, CounterActionParams> = {
94-
state: { count: 0 },
9596
actions: {
96-
increment: (_, __, params) => {
97+
increment: params => {
9798
return state => {
9899
state.count += params
99100
}
100101
}
101-
}
102+
},
103+
state: { count: 0 }
102104
}
103105

104106
export const TimeoutCounter: ModelType<CounterState, CounterActionParams> = {
105-
state: { count: 0 },
106-
asyncState: async () => ({
107-
count: 1
108-
}),
109107
actions: {
110-
increment: async (_, __, params) => {
108+
increment: async (params, { state: _ }) => {
111109
await timeout(4000, {})
112110
return (state: typeof _) => {
113111
state.count += params
114112
}
115113
}
116-
}
114+
},
115+
asyncState: async () => ({
116+
count: 1
117+
}),
118+
state: { count: 0 }
117119
}
118120

119121
export const ErrorCounter: ModelType<CounterState, CounterActionParams> = {
120-
state: { count: 0 },
121122
actions: {
122123
increment: async () => {
123124
throw 'error'
124125
}
126+
},
127+
state: { count: 0 }
128+
}
129+
130+
const delayMiddleware: Middleware = async (context, restMiddlewares) => {
131+
await timeout(2000, {})
132+
context.next(restMiddlewares)
133+
}
134+
135+
const nextCounterModel: ModelType<CounterState, NextCounterActionParams> = {
136+
actions: {
137+
add: num => {
138+
return state => {
139+
state.count += num
140+
}
141+
},
142+
increment: async (num, { actions }) => {
143+
actions.add(num)
144+
await timeout(300, {})
145+
}
146+
},
147+
middlewares: [delayMiddleware, ...actionMiddlewares],
148+
state: {
149+
count: 0
125150
}
126151
}
152+
153+
export const NextCounterModel = Model(nextCounterModel)

__test__/middlewares/model.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="../index.d.ts" />
2+
import 'react-testing-library/cleanup-after-each'
3+
process.env.NODE_ENV = 'production'
4+
import { testHook } from 'react-hooks-testing-library'
5+
import { NextCounterModel } from '..'
6+
import { Model } from '../../src'
7+
8+
describe('NextModel', () => {
9+
test("allows you to customize model's middleware", async () => {
10+
let actions: any
11+
let state: any
12+
const { useStore, getActions } = Model({ NextCounterModel })
13+
const beginTime = Date.now()
14+
testHook(() => {
15+
;[state, actions] = useStore('NextCounterModel')
16+
})
17+
await actions.increment(2)
18+
await getActions('NextCounterModel').increment(1)
19+
expect(Date.now() - beginTime > 300)
20+
expect(state.count).toBe(3)
21+
})
22+
})

0 commit comments

Comments
 (0)