This repository has been archived by the owner on Jan 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
redux.ts
108 lines (103 loc) · 3.37 KB
/
redux.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
96
97
98
99
100
101
102
103
104
105
106
107
108
import { Dispatch, ReducersMapObject, Reducer } from 'redux'
import { MapDispatchToPropsFactory } from 'react-redux'
import { CombinedReducersMapObject } from '../interfaces/store'
import { AnyAction } from '../actions/actions'
/**
* Combines a dictionary of reducers for different slices of the store into one
* root reducer.
*
* Effectively works like default redux `combineReducers` but provides access to the store
* via the third argument to allow reducers read only access to other slices
* (simplifies callbacks, epics and actions' payloads).
*
* @param reducers A dictionary of reducers for different slices of the redux store
* @category Utils
*/
export function combineReducers<State>(
reducers: ReducersMapObject<State, AnyAction> | CombinedReducersMapObject<State, AnyAction>
): Reducer<State, AnyAction> {
const combination: Reducer<State, AnyAction> = (state = {} as State, action: AnyAction) => {
const nextState = { ...state }
let hasChanged = false
for (const reducerName in reducers) {
if (!Object.prototype.hasOwnProperty.call(reducers, reducerName)) {
continue
}
const prevStateForKey = state[reducerName]
const reducer = reducers[reducerName]
const nextStateForKey = (reducer as any)(prevStateForKey, action, nextState) as State[Extract<keyof State, string>]
nextState[reducerName] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== prevStateForKey
}
return hasChanged ? nextState : state
}
return combination
}
/**
* Shallow compare of two dictionaries by strict comparison.
* `ignore` argument can be used to forcefully exclude some properties from result set even if their
* are different.
*
* TODO: Check if possible to replace with `shallowEqual` from `react-redux`
*
* @param prevProps
* @param nextProps
* @param ignore
*/
export function shallowCompare(prevProps: Record<string, any>, nextProps: Record<string, any>, ignore: string[] = []) {
const diffProps: string[] = []
if (!prevProps && !nextProps) {
return null
}
if (!prevProps) {
return Object.keys(nextProps)
}
if (!nextProps) {
return Object.keys(prevProps)
}
const newKeys = Object.keys(nextProps)
newKeys.forEach(key => {
if (prevProps[key] !== nextProps[key] && !ignore.includes(key)) {
diffProps.push(key)
}
})
Object.keys(prevProps).forEach(key => {
if (!newKeys.includes(key)) {
diffProps.push(key)
}
})
return diffProps
}
/**
* TODO: JSDoc
*/
class ActionsContext<T> {
/**
* TODO
*/
dispatch: Dispatch<any> = null
/**
* TODO
*/
props: T = null
}
/**
* TODO: JSDoc
*
* @param contextCreator
* @param actionsCreator
*/
export function createMapDispatchToProps<ContextProps, Actions, OwnProps>(
contextCreator: (props: OwnProps) => ContextProps,
actionsCreator: (context: ActionsContext<ContextProps>) => Actions
): MapDispatchToPropsFactory<Actions, OwnProps> {
return (initDispatch, initProps) => {
const context = new ActionsContext<ContextProps>()
const actions = actionsCreator(context)
context.dispatch = initDispatch
return (dispatch, props) => {
context.props = contextCreator(props)
return actions
}
}
}