-
Notifications
You must be signed in to change notification settings - Fork 1
/
reducer.ts
95 lines (89 loc) · 2.61 KB
/
reducer.ts
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { merge, Observable, Subject, Subscription } from 'rxjs';
import {
distinctUntilChanged,
map,
scan,
share,
startWith,
} from 'rxjs/operators';
// export function createDeRxJSReducer<K, T>: DeRxJSViewModel<K, T>;
export function createDeRxJSReducer<ViewModelType, ActionsUnionType>({
reducer,
effects,
sideEffects,
incomingObservables,
teardownFn,
initialState,
}: DeRxJSReducerInputs<
ViewModelType,
ActionsUnionType
>): Observable<ViewModelType> {
const actionsSubject = new Subject<ActionsUnionType>();
const actions$ = merge(...Object.values(incomingObservables)).pipe(
share({ connector: () => actionsSubject })
);
const state$ = actions$.pipe(
scan(reducer, initialState),
startWith<ViewModelType>(initialState),
distinctUntilChanged()
);
const subscriptions = new Subscription();
if (teardownFn) {
const teardown = async () => {
await teardownFn();
subscriptions.unsubscribe();
};
teardown();
}
for (const effect of effects) {
subscriptions.add(
effect(state$, actionsSubject)
.pipe(share({ connector: () => actionsSubject }))
.subscribe()
);
}
for (const sideEffect of sideEffects) {
subscriptions.add(sideEffect(state$, actionsSubject).subscribe());
}
return state$;
}
export interface DeRxJSReducerInputs<ViewModelType, ActionsUnionType> {
reducer: (a: ViewModelType, b: ActionsUnionType) => ViewModelType;
effects: ((
state$: Observable<ViewModelType>,
actions: Observable<ActionsUnionType>
) => Observable<ActionsUnionType>)[];
// | (() => ActionsUnionType)
// | (() => Promise<ActionsUnionType>))[];
sideEffects: ((
state$: Observable<ViewModelType>,
actions: Observable<ActionsUnionType>
) => Observable<any>)[];
// | (() => any) | (() => Promise<any>);
incomingObservables: {
[x: string]: Observable<ActionsUnionType>;
};
teardownFn?: () => Promise<void>;
initialState: ViewModelType;
}
export type Action<K extends string, T extends any> = {
type: K;
} & T;
// export type ActionCreator<K extends string, T extends any> = (
// data?: T
// ) => Action<K, T>;
// export function createAction<T extends any, K extends string>(
// type: K
// ): ActionCreator<K, T> {
// const actionCreatorComposer = (x: K) => (data?: T) => ({
// type: x,
// ...(data || {}),
// });
// const actionCreator = actionCreatorComposer(type);
// return actionCreator;
// }
export function actionize<K extends string, T>(actionName: K) {
return function (inc$: Observable<T>): Observable<{ type: K } & T> {
return inc$.pipe(map((x) => ({ type: actionName, ...x })));
};
}