@@ -168,18 +168,20 @@ export default function connectAdvanced(
168
168
// Retrieve the store and ancestor subscription via context, if available
169
169
const contextValue = useContext ( ContextToUse )
170
170
171
-
172
171
// The store _must_ exist as either a prop or in context
172
+ const didStoreComeFromProps = Boolean ( props . store )
173
+ const didStoreComeFromContext =
174
+ Boolean ( contextValue ) && Boolean ( contextValue . store )
175
+
173
176
invariant (
174
- props . store || contextValue ,
177
+ didStoreComeFromProps || didStoreComeFromContext ,
175
178
`Could not find "store" in the context of ` +
176
179
`"${ displayName } ". Either wrap the root component in a <Provider>, ` +
177
180
`or pass a custom React context provider to <Provider> and the corresponding ` +
178
181
`React context consumer to ${ displayName } in connect options.`
179
182
)
180
183
181
184
const store = props . store || contextValue . store
182
- const propsMode = Boolean ( props . store )
183
185
184
186
const childPropsSelector = useMemo ( ( ) => {
185
187
// The child props selector needs the store reference as an input.
@@ -190,9 +192,12 @@ export default function connectAdvanced(
190
192
const [ subscription , notifyNestedSubs ] = useMemo ( ( ) => {
191
193
if ( ! shouldHandleStateChanges ) return NO_SUBSCRIPTION_ARRAY
192
194
193
- // parentSub 's source should match where store came from: props vs. context. A component
195
+ // This Subscription 's source should match where store came from: props vs. context. A component
194
196
// connected to the store via props shouldn't use subscription from context, or vice versa.
195
- const subscription = new Subscription ( store , contextValue . subscription )
197
+ const subscription = new Subscription (
198
+ store ,
199
+ didStoreComeFromProps ? null : contextValue . subscription
200
+ )
196
201
197
202
// `notifyNestedSubs` is duplicated to handle the case where the component is unmounted in
198
203
// the middle of the notification loop, where `subscription` will then be null. This can
@@ -203,26 +208,32 @@ export default function connectAdvanced(
203
208
)
204
209
205
210
return [ subscription , notifyNestedSubs ]
206
- } , [ store , contextValue . subscription ] )
211
+ } , [ store , didStoreComeFromProps , contextValue ] )
207
212
208
- // Determine what {store, subscription} value should be put into nested context, if necessary
213
+ // Determine what {store, subscription} value should be put into nested context, if necessary,
214
+ // and memoize that value to avoid unnecessary context updates.
209
215
const overriddenContextValue = useMemo ( ( ) => {
216
+ if ( didStoreComeFromProps ) {
217
+ // This component is directly subscribed to a store from props.
218
+ // We don't want descendants reading from this store - pass down whatever
219
+ // the existing context value is from the nearest connected ancestor.
220
+ return contextValue
221
+ }
210
222
211
223
// Otherwise, put this component's subscription instance into context, so that
212
224
// connected descendants won't update until after this component is done
213
225
return {
214
226
...contextValue ,
215
227
subscription
216
228
}
217
- } , [ contextValue , subscription ] )
229
+ } , [ didStoreComeFromProps , contextValue , subscription ] )
218
230
219
231
// We need to force this wrapper component to re-render whenever a Redux store update
220
232
// causes a change to the calculated child component props (or we caught an error in mapState)
221
- const [ [ previousStateUpdateResult ] , forceComponentUpdateDispatch ] = useReducer (
222
- storeStateUpdatesReducer ,
223
- EMPTY_ARRAY ,
224
- initStateUpdates
225
- )
233
+ const [
234
+ [ previousStateUpdateResult ] ,
235
+ forceComponentUpdateDispatch
236
+ ] = useReducer ( storeStateUpdatesReducer , EMPTY_ARRAY , initStateUpdates )
226
237
227
238
// Propagate any mapState/mapDispatch errors upwards
228
239
if ( previousStateUpdateResult && previousStateUpdateResult . error ) {
0 commit comments