forked from coldemo/gallery.code
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuse-model.jsx
More file actions
68 lines (59 loc) · 1.66 KB
/
use-model.jsx
File metadata and controls
68 lines (59 loc) · 1.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
await loadJs([
'https://unpkg.com/[email protected]/dist/immer.umd.production.min.js',
'https://unpkg.com/[email protected]/dist/index.js',
])
let { produce } = immer
let { Button } = Antd
let { Editor } = ReactEditor
let App = () => {
let [state, actions] = useModel(produce((draft, action) => {
if (action.type === 'increase') draft.count += 1
}), { count: 0 }, {
increase: () => null
})
useInterval(() => {
actions.increase()
}, 1000)
return (
<div style={{ padding: 20 }}>
<h1>{state.count}</h1>
<Button type="primary" onClick={actions.increase}>Add</Button>
<Editor defaultValue={state.count} placeholder="Type something..." style={{ border: 'solid 1px gray', marginTop: 20, padding: '4px 10px', height: 200, overflow: 'auto' }} />
</div>
)
}
/**
* useModel.ts
```ts
import _ from 'lodash';
import { Reducer, useMemo, useReducer } from 'react';
interface ActionArgMap<A> {
[type: string]: (...args: any[]) => Omit<A, 'type'> | null;
}
interface ActionMap<A> {
[type: string]: (...args: any[]) => A;
}
export let useModel = <S, A extends { type: string }>(
reducer: Reducer<S, A>,
initialState: S,
_actions: ActionArgMap<A>
) => {
let [state, dispatch] = useReducer<Reducer<S, A>>(reducer, initialState);
let actions = useMemo<ActionMap<A>>(() => {
return _.reduce(
_actions,
(acc, func, k) => {
acc[k] = (...args: any[]) => {
let patch = func(...args);
let action = { type: k, ...patch } as A;
return dispatch(action);
};
return acc;
},
Object.create(null)
);
}, [_actions, dispatch]);
return [state, actions];
};
```
*/