@@ -14,6 +14,13 @@ const defaultMergeProps = (stateProps, dispatchProps, parentProps) => ({
14
14
...dispatchProps
15
15
} )
16
16
17
+ function isFunction ( fn ) {
18
+ return typeof fn === 'function'
19
+ }
20
+ function isFactory ( fn ) {
21
+ return isFunction ( fn ) && fn . length === 0 && isFunction ( fn ( ) )
22
+ }
23
+
17
24
function getDisplayName ( WrappedComponent ) {
18
25
return WrappedComponent . displayName || WrappedComponent . name || 'Component'
19
26
}
@@ -23,56 +30,20 @@ let nextVersion = 0
23
30
24
31
export default function connect ( mapStateToProps , mapDispatchToProps , mergeProps , options = { } ) {
25
32
const shouldSubscribe = Boolean ( mapStateToProps )
26
- const finalMapStateToProps = mapStateToProps || defaultMapStateToProps
27
- const finalMapDispatchToProps = isPlainObject ( mapDispatchToProps ) ?
33
+ const mapState = mapStateToProps || defaultMapStateToProps
34
+ const mapDispatch = isPlainObject ( mapDispatchToProps ) ?
28
35
wrapActionCreators ( mapDispatchToProps ) :
29
36
mapDispatchToProps || defaultMapDispatchToProps
37
+
38
+ const mapStateFactory = isFactory ( mapState ) ? mapState : ( ( ) => mapState )
39
+ const mapDispatchFactory = isFactory ( mapDispatch ) ? mapDispatch : ( ( ) => mapDispatch )
40
+
30
41
const finalMergeProps = mergeProps || defaultMergeProps
31
- const doStatePropsDependOnOwnProps = finalMapStateToProps . length !== 1
32
- const doDispatchPropsDependOnOwnProps = finalMapDispatchToProps . length !== 1
33
42
const { pure = true , withRef = false } = options
34
43
35
44
// Helps track hot reloading.
36
45
const version = nextVersion ++
37
46
38
- function computeStateProps ( store , props ) {
39
- const state = store . getState ( )
40
- const stateProps = doStatePropsDependOnOwnProps ?
41
- finalMapStateToProps ( state , props ) :
42
- finalMapStateToProps ( state )
43
-
44
- invariant (
45
- isPlainObject ( stateProps ) ,
46
- '`mapStateToProps` must return an object. Instead received %s.' ,
47
- stateProps
48
- )
49
- return stateProps
50
- }
51
-
52
- function computeDispatchProps ( store , props ) {
53
- const { dispatch } = store
54
- const dispatchProps = doDispatchPropsDependOnOwnProps ?
55
- finalMapDispatchToProps ( dispatch , props ) :
56
- finalMapDispatchToProps ( dispatch )
57
-
58
- invariant (
59
- isPlainObject ( dispatchProps ) ,
60
- '`mapDispatchToProps` must return an object. Instead received %s.' ,
61
- dispatchProps
62
- )
63
- return dispatchProps
64
- }
65
-
66
- function computeMergedProps ( stateProps , dispatchProps , parentProps ) {
67
- const mergedProps = finalMergeProps ( stateProps , dispatchProps , parentProps )
68
- invariant (
69
- isPlainObject ( mergedProps ) ,
70
- '`mergeProps` must return an object. Instead received %s.' ,
71
- mergedProps
72
- )
73
- return mergedProps
74
- }
75
-
76
47
return function wrapWithConnect ( WrappedComponent ) {
77
48
class Connect extends Component {
78
49
shouldComponentUpdate ( ) {
@@ -91,13 +62,59 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
91
62
`or explicitly pass "store" as a prop to "${ this . constructor . displayName } ".`
92
63
)
93
64
65
+ this . configure ( )
94
66
const storeState = this . store . getState ( )
95
67
this . state = { storeState }
96
68
this . clearCache ( )
97
69
}
98
70
71
+ configure ( ) {
72
+ this . finalMapStateToProps = mapStateFactory ( )
73
+ this . finalMapDispatchToProps = mapDispatchFactory ( )
74
+ this . doStatePropsDependOnOwnProps = this . finalMapStateToProps . length !== 1
75
+ this . doDispatchPropsDependOnOwnProps = this . finalMapDispatchToProps . length !== 1
76
+ }
77
+
78
+ computeStateProps ( store , props ) {
79
+ const state = store . getState ( )
80
+ const stateProps = this . doStatePropsDependOnOwnProps ?
81
+ this . finalMapStateToProps ( state , props ) :
82
+ this . finalMapStateToProps ( state )
83
+
84
+ invariant (
85
+ isPlainObject ( stateProps ) ,
86
+ '`mapStateToProps` must return an object. Instead received %s.' ,
87
+ stateProps
88
+ )
89
+ return stateProps
90
+ }
91
+
92
+ computeDispatchProps ( store , props ) {
93
+ const { dispatch } = store
94
+ const dispatchProps = this . doDispatchPropsDependOnOwnProps ?
95
+ this . finalMapDispatchToProps ( dispatch , props ) :
96
+ this . finalMapDispatchToProps ( dispatch )
97
+
98
+ invariant (
99
+ isPlainObject ( dispatchProps ) ,
100
+ '`mapDispatchToProps` must return an object. Instead received %s.' ,
101
+ dispatchProps
102
+ )
103
+ return dispatchProps
104
+ }
105
+
106
+ computeMergedProps ( stateProps , dispatchProps , parentProps ) {
107
+ const mergedProps = finalMergeProps ( stateProps , dispatchProps , parentProps )
108
+ invariant (
109
+ isPlainObject ( mergedProps ) ,
110
+ '`mergeProps` must return an object. Instead received %s.' ,
111
+ mergedProps
112
+ )
113
+ return mergedProps
114
+ }
115
+
99
116
updateStatePropsIfNeeded ( ) {
100
- const nextStateProps = computeStateProps ( this . store , this . props )
117
+ const nextStateProps = this . computeStateProps ( this . store , this . props )
101
118
if ( this . stateProps && shallowEqual ( nextStateProps , this . stateProps ) ) {
102
119
return false
103
120
}
@@ -107,7 +124,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
107
124
}
108
125
109
126
updateDispatchPropsIfNeeded ( ) {
110
- const nextDispatchProps = computeDispatchProps ( this . store , this . props )
127
+ const nextDispatchProps = this . computeDispatchProps ( this . store , this . props )
111
128
if ( this . dispatchProps && shallowEqual ( nextDispatchProps , this . dispatchProps ) ) {
112
129
return false
113
130
}
@@ -117,15 +134,15 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
117
134
}
118
135
119
136
updateMergedProps ( ) {
120
- this . mergedProps = computeMergedProps (
137
+ this . mergedProps = this . computeMergedProps (
121
138
this . stateProps ,
122
139
this . dispatchProps ,
123
140
this . props
124
141
)
125
142
}
126
143
127
144
isSubscribed ( ) {
128
- return typeof this . unsubscribe === 'function'
145
+ return isFunction ( this . unsubscribe )
129
146
}
130
147
131
148
trySubscribe ( ) {
@@ -203,10 +220,10 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
203
220
let shouldUpdateDispatchProps = true
204
221
if ( pure && renderedElement ) {
205
222
shouldUpdateStateProps = hasStoreStateChanged || (
206
- haveOwnPropsChanged && doStatePropsDependOnOwnProps
223
+ haveOwnPropsChanged && this . doStatePropsDependOnOwnProps
207
224
)
208
225
shouldUpdateDispatchProps =
209
- haveOwnPropsChanged && doDispatchPropsDependOnOwnProps
226
+ haveOwnPropsChanged && this . doDispatchPropsDependOnOwnProps
210
227
}
211
228
212
229
let haveStatePropsChanged = false
@@ -265,6 +282,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
265
282
266
283
// We are hot reloading!
267
284
this . version = version
285
+ this . configure ( )
268
286
this . trySubscribe ( )
269
287
this . clearCache ( )
270
288
}
0 commit comments