@@ -19,7 +19,7 @@ import defaultSelectorFactory, {
19
19
MapDispatchToPropsParam ,
20
20
MergeProps ,
21
21
MapDispatchToPropsNonObject ,
22
- SelectorFactory ,
22
+ SelectorFactoryOptions ,
23
23
} from '../connect/selectorFactory'
24
24
import defaultMapDispatchToPropsFactories from '../connect/mapDispatchToProps'
25
25
import defaultMapStateToPropsFactories from '../connect/mapStateToProps'
@@ -205,152 +205,406 @@ export interface ConnectProps {
205
205
store ?: Store
206
206
}
207
207
208
- export interface ConnectAdvancedOptions {
209
- shouldHandleStateChanges ?: boolean
210
- forwardRef ?: boolean
211
- context ?: typeof ReactReduxContext
212
- pure ?: boolean
213
- }
214
-
215
- function connectAdvanced < S , TProps , TOwnProps , TFactoryOptions = { } > (
216
- /*
217
- selectorFactory is a func that is responsible for returning the selector function used to
218
- compute new props from state, props, and dispatch. For example:
219
-
220
- export default connectAdvanced((dispatch, options) => (state, props) => ({
221
- thing: state.things[props.thingId],
222
- saveThing: fields => dispatch(actionCreators.saveThing(props.thingId, fields)),
223
- }))(YourComponent)
224
-
225
- Access to dispatch is provided to the factory so selectorFactories can bind actionCreators
226
- outside of their selector as an optimization. Options passed to connectAdvanced are passed to
227
- the selectorFactory, along with displayName and WrappedComponent, as the second argument.
228
-
229
- Note that selectorFactory is responsible for all caching/memoization of inbound and outbound
230
- props. Do not use connectAdvanced directly without memoizing results between calls to your
231
- selector, otherwise the Connect component will re-render on every state or props change.
232
- */
233
- selectorFactory : SelectorFactory < S , TProps , unknown , unknown > ,
234
- // options object:
235
- {
236
- // determines whether this HOC subscribes to store changes
237
- shouldHandleStateChanges = true ,
208
+ function match < T > (
209
+ arg : unknown ,
210
+ factories : ( ( value : unknown ) => T ) [ ] ,
211
+ name : string
212
+ ) : T {
213
+ for ( let i = factories . length - 1 ; i >= 0 ; i -- ) {
214
+ const result = factories [ i ] ( arg )
215
+ if ( result ) return result
216
+ }
238
217
239
- // use React's forwardRef to expose a ref of the wrapped component
240
- forwardRef = false ,
218
+ return ( ( dispatch : Dispatch , options : { wrappedComponentName : string } ) => {
219
+ throw new Error (
220
+ `Invalid value of type ${ typeof arg } for ${ name } argument when connecting component ${
221
+ options . wrappedComponentName
222
+ } .`
223
+ )
224
+ } ) as any
225
+ }
241
226
242
- // the context consumer to use
243
- context = ReactReduxContext ,
227
+ function strictEqual ( a : unknown , b : unknown ) {
228
+ return a === b
229
+ }
244
230
245
- // additional options are passed through to the selectorFactory
246
- ...connectOptions
247
- } : ConnectAdvancedOptions & Partial < TFactoryOptions > = { }
248
- ) {
249
- const Context = context
231
+ /**
232
+ * Infers the type of props that a connector will inject into a component.
233
+ */
234
+ export type ConnectedProps < TConnector > =
235
+ TConnector extends InferableComponentEnhancerWithProps <
236
+ infer TInjectedProps ,
237
+ any
238
+ >
239
+ ? unknown extends TInjectedProps
240
+ ? TConnector extends InferableComponentEnhancer < infer TInjectedProps >
241
+ ? TInjectedProps
242
+ : never
243
+ : TInjectedProps
244
+ : never
250
245
251
- type WrappedComponentProps = TOwnProps & ConnectProps
246
+ export interface ConnectOptions <
247
+ State = DefaultRootState ,
248
+ TStateProps = { } ,
249
+ TOwnProps = { } ,
250
+ TMergedProps = { }
251
+ > {
252
+ forwardRef ?: boolean
253
+ context ?: typeof ReactReduxContext
254
+ pure ?: boolean
255
+ areStatesEqual ?: ( nextState : State , prevState : State ) => boolean
252
256
253
- const wrapWithConnect : AdvancedComponentDecorator <
254
- TProps ,
255
- WrappedComponentProps
256
- > = ( WrappedComponent ) => {
257
- if (
258
- process . env . NODE_ENV !== 'production' &&
259
- ! isValidElementType ( WrappedComponent )
260
- ) {
261
- throw new Error (
262
- `You must pass a component to the function returned by connect. Instead received ${ stringifyComponent (
263
- WrappedComponent
264
- ) } `
265
- )
266
- }
257
+ areOwnPropsEqual ?: (
258
+ nextOwnProps : TOwnProps ,
259
+ prevOwnProps : TOwnProps
260
+ ) => boolean
267
261
268
- const wrappedComponentName =
269
- WrappedComponent . displayName || WrappedComponent . name || 'Component'
262
+ areStatePropsEqual ?: (
263
+ nextStateProps : TStateProps ,
264
+ prevStateProps : TStateProps
265
+ ) => boolean
266
+ areMergedPropsEqual ?: (
267
+ nextMergedProps : TMergedProps ,
268
+ prevMergedProps : TMergedProps
269
+ ) => boolean
270
+ }
270
271
271
- const displayName = `Connect(${ wrappedComponentName } )`
272
+ /* @public */
273
+ function connect ( ) : InferableComponentEnhancer < DispatchProp >
272
274
273
- const selectorFactoryOptions = {
274
- ...connectOptions ,
275
- shouldHandleStateChanges,
276
- displayName,
277
- wrappedComponentName,
278
- WrappedComponent,
279
- }
275
+ /* @public */
276
+ function connect <
277
+ TStateProps = { } ,
278
+ no_dispatch = { } ,
279
+ TOwnProps = { } ,
280
+ State = DefaultRootState
281
+ > (
282
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State >
283
+ ) : InferableComponentEnhancerWithProps < TStateProps & DispatchProp , TOwnProps >
280
284
281
- const { pure } = connectOptions
285
+ /* @public */
286
+ function connect < no_state = { } , TDispatchProps = { } , TOwnProps = { } > (
287
+ mapStateToProps : null | undefined ,
288
+ mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps >
289
+ ) : InferableComponentEnhancerWithProps < TDispatchProps , TOwnProps >
282
290
283
- // If we aren't running in "pure" mode, we don't want to memoize values.
284
- // To avoid conditionally calling hooks, we fall back to a tiny wrapper
285
- // that just executes the given callback immediately.
286
- const usePureOnlyMemo = pure
287
- ? useMemo
288
- : ( callback : ( ) => void ) => callback ( )
291
+ /* @public */
292
+ function connect < no_state = { } , TDispatchProps = { } , TOwnProps = { } > (
293
+ mapStateToProps : null | undefined ,
294
+ mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps >
295
+ ) : InferableComponentEnhancerWithProps < ResolveThunks < TDispatchProps > , TOwnProps >
289
296
290
- function ConnectFunction < TOwnProps > ( props : ConnectProps & TOwnProps ) {
291
- const [ propsContext , reactReduxForwardedRef , wrapperProps ] =
292
- useMemo ( ( ) => {
293
- // Distinguish between actual "data" props that were passed to the wrapper component,
294
- // and values needed to control behavior (forwarded refs, alternate context instances).
295
- // To maintain the wrapperProps object reference, memoize this destructuring.
296
- const { reactReduxForwardedRef, ...wrapperProps } = props
297
- return [ props . context , reactReduxForwardedRef , wrapperProps ]
298
- } , [ props ] )
297
+ /* @public */
298
+ function connect <
299
+ TStateProps = { } ,
300
+ TDispatchProps = { } ,
301
+ TOwnProps = { } ,
302
+ State = DefaultRootState
303
+ > (
304
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
305
+ mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps >
306
+ ) : InferableComponentEnhancerWithProps < TStateProps & TDispatchProps , TOwnProps >
299
307
300
- const ContextToUse : ReactReduxContextInstance = useMemo ( ( ) => {
301
- // Users may optionally pass in a custom context instance to use instead of our ReactReduxContext.
302
- // Memoize the check that determines which context instance we should use.
303
- return propsContext &&
304
- propsContext . Consumer &&
305
- // @ts -ignore
306
- isContextConsumer ( < propsContext . Consumer /> )
307
- ? propsContext
308
- : Context
309
- } , [ propsContext , Context ] )
308
+ /* @public */
309
+ function connect <
310
+ TStateProps = { } ,
311
+ TDispatchProps = { } ,
312
+ TOwnProps = { } ,
313
+ State = DefaultRootState
314
+ > (
315
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
316
+ mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps >
317
+ ) : InferableComponentEnhancerWithProps <
318
+ TStateProps & ResolveThunks < TDispatchProps > ,
319
+ TOwnProps
320
+ >
310
321
311
- // Retrieve the store and ancestor subscription via context, if available
312
- const contextValue = useContext ( ContextToUse )
322
+ /* @public */
323
+ function connect <
324
+ no_state = { } ,
325
+ no_dispatch = { } ,
326
+ TOwnProps = { } ,
327
+ TMergedProps = { }
328
+ > (
329
+ mapStateToProps : null | undefined ,
330
+ mapDispatchToProps : null | undefined ,
331
+ mergeProps : MergeProps < undefined , undefined , TOwnProps , TMergedProps >
332
+ ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
313
333
314
- // The store _must_ exist as either a prop or in context.
315
- // We'll check to see if it _looks_ like a Redux store first.
316
- // This allows us to pass through a `store` prop that is just a plain value.
317
- const didStoreComeFromProps =
318
- Boolean ( props . store ) &&
319
- Boolean ( props . store ! . getState ) &&
320
- Boolean ( props . store ! . dispatch )
321
- const didStoreComeFromContext =
322
- Boolean ( contextValue ) && Boolean ( contextValue ! . store )
334
+ /* @public */
335
+ function connect <
336
+ TStateProps = { } ,
337
+ no_dispatch = { } ,
338
+ TOwnProps = { } ,
339
+ TMergedProps = { } ,
340
+ State = DefaultRootState
341
+ > (
342
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
343
+ mapDispatchToProps : null | undefined ,
344
+ mergeProps : MergeProps < TStateProps , undefined , TOwnProps , TMergedProps >
345
+ ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
323
346
324
- if (
325
- process . env . NODE_ENV !== 'production' &&
326
- ! didStoreComeFromProps &&
327
- ! didStoreComeFromContext
328
- ) {
329
- throw new Error (
330
- `Could not find "store" in the context of ` +
331
- `"${ displayName } ". Either wrap the root component in a <Provider>, ` +
332
- `or pass a custom React context provider to <Provider> and the corresponding ` +
333
- `React context consumer to ${ displayName } in connect options.`
334
- )
335
- }
347
+ /* @public */
348
+ function connect <
349
+ no_state = { } ,
350
+ TDispatchProps = { } ,
351
+ TOwnProps = { } ,
352
+ TMergedProps = { }
353
+ > (
354
+ mapStateToProps : null | undefined ,
355
+ mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
356
+ mergeProps : MergeProps < undefined , TDispatchProps , TOwnProps , TMergedProps >
357
+ ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
336
358
337
- // Based on the previous check, one of these must be true
338
- const store : Store = didStoreComeFromProps
339
- ? props . store !
340
- : contextValue ! . store
359
+ /* @public */
360
+ // @ts -ignore
361
+ function connect <
362
+ TStateProps = { } ,
363
+ no_dispatch = { } ,
364
+ TOwnProps = { } ,
365
+ State = DefaultRootState
366
+ > (
367
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
368
+ mapDispatchToProps : null | undefined ,
369
+ mergeProps : null | undefined ,
370
+ options : ConnectOptions < State , TStateProps , TOwnProps >
371
+ ) : InferableComponentEnhancerWithProps < DispatchProp & TStateProps , TOwnProps >
341
372
342
- const childPropsSelector = useMemo ( ( ) => {
343
- // The child props selector needs the store reference as an input.
344
- // Re-create this selector whenever the store changes.
345
- return selectorFactory ( store . dispatch , selectorFactoryOptions )
346
- } , [ store ] )
373
+ /* @public */
374
+ function connect < TStateProps = { } , TDispatchProps = { } , TOwnProps = { } > (
375
+ mapStateToProps : null | undefined ,
376
+ mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps > ,
377
+ mergeProps : null | undefined ,
378
+ options : ConnectOptions < { } , TStateProps , TOwnProps >
379
+ ) : InferableComponentEnhancerWithProps < TDispatchProps , TOwnProps >
347
380
348
- const [ subscription , notifyNestedSubs ] = useMemo ( ( ) => {
349
- if ( ! shouldHandleStateChanges ) return NO_SUBSCRIPTION_ARRAY
381
+ /* @public */
382
+ function connect < TStateProps = { } , TDispatchProps = { } , TOwnProps = { } > (
383
+ mapStateToProps : null | undefined ,
384
+ mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
385
+ mergeProps : null | undefined ,
386
+ options : ConnectOptions < { } , TStateProps , TOwnProps >
387
+ ) : InferableComponentEnhancerWithProps < ResolveThunks < TDispatchProps > , TOwnProps >
350
388
351
- // This Subscription's source should match where store came from: props vs. context. A component
352
- // connected to the store via props shouldn't use subscription from context, or vice versa.
353
- const subscription = createSubscription (
389
+ /* @public */
390
+ function connect <
391
+ TStateProps = { } ,
392
+ TDispatchProps = { } ,
393
+ TOwnProps = { } ,
394
+ State = DefaultRootState
395
+ > (
396
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
397
+ mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps > ,
398
+ mergeProps : null | undefined ,
399
+ options : ConnectOptions < State , TStateProps , TOwnProps >
400
+ ) : InferableComponentEnhancerWithProps < TStateProps & TDispatchProps , TOwnProps >
401
+
402
+ /* @public */
403
+ function connect <
404
+ TStateProps = { } ,
405
+ TDispatchProps = { } ,
406
+ TOwnProps = { } ,
407
+ State = DefaultRootState
408
+ > (
409
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
410
+ mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
411
+ mergeProps : null | undefined ,
412
+ options : ConnectOptions < State , TStateProps , TOwnProps >
413
+ ) : InferableComponentEnhancerWithProps <
414
+ TStateProps & ResolveThunks < TDispatchProps > ,
415
+ TOwnProps
416
+ >
417
+
418
+ /* @public */
419
+ function connect <
420
+ TStateProps = { } ,
421
+ TDispatchProps = { } ,
422
+ TOwnProps = { } ,
423
+ TMergedProps = { } ,
424
+ State = DefaultRootState
425
+ > (
426
+ mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
427
+ mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
428
+ mergeProps : MergeProps < TStateProps , TDispatchProps , TOwnProps , TMergedProps > ,
429
+ options ?: ConnectOptions < State , TStateProps , TOwnProps , TMergedProps >
430
+ ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
431
+
432
+ /**
433
+ * Connects a React component to a Redux store.
434
+ *
435
+ * - Without arguments, just wraps the component, without changing the behavior / props
436
+ *
437
+ * - If 2 params are passed (3rd param, mergeProps, is skipped), default behavior
438
+ * is to override ownProps (as stated in the docs), so what remains is everything that's
439
+ * not a state or dispatch prop
440
+ *
441
+ * - When 3rd param is passed, we don't know if ownProps propagate and whether they
442
+ * should be valid component props, because it depends on mergeProps implementation.
443
+ * As such, it is the user's responsibility to extend ownProps interface from state or
444
+ * dispatch props or both when applicable
445
+ *
446
+ * @param mapStateToProps A function that extracts values from state
447
+ * @param mapDispatchToProps Setup for dispatching actions
448
+ * @param mergeProps Optional callback to merge state and dispatch props together
449
+ * @param options Options for configuring the connection
450
+ *
451
+ */
452
+ function connect <
453
+ TStateProps = { } ,
454
+ TDispatchProps = { } ,
455
+ TOwnProps = { } ,
456
+ TMergedProps = { } ,
457
+ State = DefaultRootState
458
+ > (
459
+ mapStateToProps ?: MapStateToPropsParam < TStateProps , TOwnProps , State > ,
460
+ mapDispatchToProps ?: MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
461
+ mergeProps ?: MergeProps < TStateProps , TDispatchProps , TOwnProps , TMergedProps > ,
462
+ {
463
+ pure = true ,
464
+ areStatesEqual = strictEqual ,
465
+ areOwnPropsEqual = shallowEqual ,
466
+ areStatePropsEqual = shallowEqual ,
467
+ areMergedPropsEqual = shallowEqual ,
468
+
469
+ // use React's forwardRef to expose a ref of the wrapped component
470
+ forwardRef = false ,
471
+
472
+ // the context consumer to use
473
+ context = ReactReduxContext ,
474
+ } : ConnectOptions < unknown , unknown , unknown , unknown > = { }
475
+ ) : unknown {
476
+ const Context = context
477
+
478
+ type WrappedComponentProps = TOwnProps & ConnectProps
479
+
480
+ const initMapStateToProps = match (
481
+ mapStateToProps ,
482
+ // @ts -ignore
483
+ defaultMapStateToPropsFactories ,
484
+ 'mapStateToProps'
485
+ ) !
486
+ const initMapDispatchToProps = match (
487
+ mapDispatchToProps ,
488
+ // @ts -ignore
489
+ defaultMapDispatchToPropsFactories ,
490
+ 'mapDispatchToProps'
491
+ ) !
492
+ const initMergeProps = match (
493
+ mergeProps ,
494
+ // @ts -ignore
495
+ defaultMergePropsFactories ,
496
+ 'mergeProps'
497
+ ) !
498
+
499
+ const shouldHandleStateChanges = Boolean ( mapStateToProps )
500
+
501
+ const wrapWithConnect : AdvancedComponentDecorator <
502
+ TOwnProps ,
503
+ WrappedComponentProps
504
+ > = ( WrappedComponent ) => {
505
+ if (
506
+ process . env . NODE_ENV !== 'production' &&
507
+ ! isValidElementType ( WrappedComponent )
508
+ ) {
509
+ throw new Error (
510
+ `You must pass a component to the function returned by connect. Instead received ${ stringifyComponent (
511
+ WrappedComponent
512
+ ) } `
513
+ )
514
+ }
515
+
516
+ const wrappedComponentName =
517
+ WrappedComponent . displayName || WrappedComponent . name || 'Component'
518
+
519
+ const displayName = `Connect(${ wrappedComponentName } )`
520
+
521
+ const selectorFactoryOptions : SelectorFactoryOptions < any , any , any , any > = {
522
+ pure,
523
+ shouldHandleStateChanges,
524
+ displayName,
525
+ wrappedComponentName,
526
+ WrappedComponent,
527
+ initMapStateToProps,
528
+ initMapDispatchToProps,
529
+ // @ts -ignore
530
+ initMergeProps,
531
+ areStatesEqual,
532
+ areStatePropsEqual,
533
+ areOwnPropsEqual,
534
+ areMergedPropsEqual,
535
+ }
536
+
537
+ // If we aren't running in "pure" mode, we don't want to memoize values.
538
+ // To avoid conditionally calling hooks, we fall back to a tiny wrapper
539
+ // that just executes the given callback immediately.
540
+ const usePureOnlyMemo = pure
541
+ ? useMemo
542
+ : ( callback : ( ) => void ) => callback ( )
543
+
544
+ function ConnectFunction < TOwnProps > ( props : ConnectProps & TOwnProps ) {
545
+ const [ propsContext , reactReduxForwardedRef , wrapperProps ] =
546
+ useMemo ( ( ) => {
547
+ // Distinguish between actual "data" props that were passed to the wrapper component,
548
+ // and values needed to control behavior (forwarded refs, alternate context instances).
549
+ // To maintain the wrapperProps object reference, memoize this destructuring.
550
+ const { reactReduxForwardedRef, ...wrapperProps } = props
551
+ return [ props . context , reactReduxForwardedRef , wrapperProps ]
552
+ } , [ props ] )
553
+
554
+ const ContextToUse : ReactReduxContextInstance = useMemo ( ( ) => {
555
+ // Users may optionally pass in a custom context instance to use instead of our ReactReduxContext.
556
+ // Memoize the check that determines which context instance we should use.
557
+ return propsContext &&
558
+ propsContext . Consumer &&
559
+ // @ts -ignore
560
+ isContextConsumer ( < propsContext . Consumer /> )
561
+ ? propsContext
562
+ : Context
563
+ } , [ propsContext , Context ] )
564
+
565
+ // Retrieve the store and ancestor subscription via context, if available
566
+ const contextValue = useContext ( ContextToUse )
567
+
568
+ // The store _must_ exist as either a prop or in context.
569
+ // We'll check to see if it _looks_ like a Redux store first.
570
+ // This allows us to pass through a `store` prop that is just a plain value.
571
+ const didStoreComeFromProps =
572
+ Boolean ( props . store ) &&
573
+ Boolean ( props . store ! . getState ) &&
574
+ Boolean ( props . store ! . dispatch )
575
+ const didStoreComeFromContext =
576
+ Boolean ( contextValue ) && Boolean ( contextValue ! . store )
577
+
578
+ if (
579
+ process . env . NODE_ENV !== 'production' &&
580
+ ! didStoreComeFromProps &&
581
+ ! didStoreComeFromContext
582
+ ) {
583
+ throw new Error (
584
+ `Could not find "store" in the context of ` +
585
+ `"${ displayName } ". Either wrap the root component in a <Provider>, ` +
586
+ `or pass a custom React context provider to <Provider> and the corresponding ` +
587
+ `React context consumer to ${ displayName } in connect options.`
588
+ )
589
+ }
590
+
591
+ // Based on the previous check, one of these must be true
592
+ const store : Store = didStoreComeFromProps
593
+ ? props . store !
594
+ : contextValue ! . store
595
+
596
+ const childPropsSelector = useMemo ( ( ) => {
597
+ // The child props selector needs the store reference as an input.
598
+ // Re-create this selector whenever the store changes.
599
+ return defaultSelectorFactory ( store . dispatch , selectorFactoryOptions )
600
+ } , [ store ] )
601
+
602
+ const [ subscription , notifyNestedSubs ] = useMemo ( ( ) => {
603
+ if ( ! shouldHandleStateChanges ) return NO_SUBSCRIPTION_ARRAY
604
+
605
+ // This Subscription's source should match where store came from: props vs. context. A component
606
+ // connected to the store via props shouldn't use subscription from context, or vice versa.
607
+ const subscription = createSubscription (
354
608
store ,
355
609
didStoreComeFromProps ? undefined : contextValue ! . subscription
356
610
)
@@ -524,301 +778,4 @@ function connectAdvanced<S, TProps, TOwnProps, TFactoryOptions = {}>(
524
778
return wrapWithConnect
525
779
}
526
780
527
- function match < T > (
528
- arg : unknown ,
529
- factories : ( ( value : unknown ) => T ) [ ] ,
530
- name : string
531
- ) : T {
532
- for ( let i = factories . length - 1 ; i >= 0 ; i -- ) {
533
- const result = factories [ i ] ( arg )
534
- if ( result ) return result
535
- }
536
-
537
- return ( ( dispatch : Dispatch , options : { wrappedComponentName : string } ) => {
538
- throw new Error (
539
- `Invalid value of type ${ typeof arg } for ${ name } argument when connecting component ${
540
- options . wrappedComponentName
541
- } .`
542
- )
543
- } ) as any
544
- }
545
-
546
- function strictEqual ( a : unknown , b : unknown ) {
547
- return a === b
548
- }
549
-
550
- /**
551
- * Infers the type of props that a connector will inject into a component.
552
- */
553
- export type ConnectedProps < TConnector > =
554
- TConnector extends InferableComponentEnhancerWithProps <
555
- infer TInjectedProps ,
556
- any
557
- >
558
- ? unknown extends TInjectedProps
559
- ? TConnector extends InferableComponentEnhancer < infer TInjectedProps >
560
- ? TInjectedProps
561
- : never
562
- : TInjectedProps
563
- : never
564
-
565
- export interface ConnectOptions <
566
- State = DefaultRootState ,
567
- TStateProps = { } ,
568
- TOwnProps = { } ,
569
- TMergedProps = { }
570
- > extends ConnectAdvancedOptions {
571
- pure ?: boolean
572
- areStatesEqual ?: ( nextState : State , prevState : State ) => boolean
573
-
574
- areOwnPropsEqual ?: (
575
- nextOwnProps : TOwnProps ,
576
- prevOwnProps : TOwnProps
577
- ) => boolean
578
-
579
- areStatePropsEqual ?: (
580
- nextStateProps : TStateProps ,
581
- prevStateProps : TStateProps
582
- ) => boolean
583
- areMergedPropsEqual ?: (
584
- nextMergedProps : TMergedProps ,
585
- prevMergedProps : TMergedProps
586
- ) => boolean
587
- forwardRef ?: boolean
588
- }
589
-
590
- /* @public */
591
- function connect ( ) : InferableComponentEnhancer < DispatchProp >
592
-
593
- /* @public */
594
- function connect <
595
- TStateProps = { } ,
596
- no_dispatch = { } ,
597
- TOwnProps = { } ,
598
- State = DefaultRootState
599
- > (
600
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State >
601
- ) : InferableComponentEnhancerWithProps < TStateProps & DispatchProp , TOwnProps >
602
-
603
- /* @public */
604
- function connect < no_state = { } , TDispatchProps = { } , TOwnProps = { } > (
605
- mapStateToProps : null | undefined ,
606
- mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps >
607
- ) : InferableComponentEnhancerWithProps < TDispatchProps , TOwnProps >
608
-
609
- /* @public */
610
- function connect < no_state = { } , TDispatchProps = { } , TOwnProps = { } > (
611
- mapStateToProps : null | undefined ,
612
- mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps >
613
- ) : InferableComponentEnhancerWithProps < ResolveThunks < TDispatchProps > , TOwnProps >
614
-
615
- /* @public */
616
- function connect <
617
- TStateProps = { } ,
618
- TDispatchProps = { } ,
619
- TOwnProps = { } ,
620
- State = DefaultRootState
621
- > (
622
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
623
- mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps >
624
- ) : InferableComponentEnhancerWithProps < TStateProps & TDispatchProps , TOwnProps >
625
-
626
- /* @public */
627
- function connect <
628
- TStateProps = { } ,
629
- TDispatchProps = { } ,
630
- TOwnProps = { } ,
631
- State = DefaultRootState
632
- > (
633
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
634
- mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps >
635
- ) : InferableComponentEnhancerWithProps <
636
- TStateProps & ResolveThunks < TDispatchProps > ,
637
- TOwnProps
638
- >
639
-
640
- /* @public */
641
- function connect <
642
- no_state = { } ,
643
- no_dispatch = { } ,
644
- TOwnProps = { } ,
645
- TMergedProps = { }
646
- > (
647
- mapStateToProps : null | undefined ,
648
- mapDispatchToProps : null | undefined ,
649
- mergeProps : MergeProps < undefined , undefined , TOwnProps , TMergedProps >
650
- ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
651
-
652
- /* @public */
653
- function connect <
654
- TStateProps = { } ,
655
- no_dispatch = { } ,
656
- TOwnProps = { } ,
657
- TMergedProps = { } ,
658
- State = DefaultRootState
659
- > (
660
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
661
- mapDispatchToProps : null | undefined ,
662
- mergeProps : MergeProps < TStateProps , undefined , TOwnProps , TMergedProps >
663
- ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
664
-
665
- /* @public */
666
- function connect <
667
- no_state = { } ,
668
- TDispatchProps = { } ,
669
- TOwnProps = { } ,
670
- TMergedProps = { }
671
- > (
672
- mapStateToProps : null | undefined ,
673
- mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
674
- mergeProps : MergeProps < undefined , TDispatchProps , TOwnProps , TMergedProps >
675
- ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
676
-
677
- /* @public */
678
- // @ts -ignore
679
- function connect <
680
- TStateProps = { } ,
681
- no_dispatch = { } ,
682
- TOwnProps = { } ,
683
- State = DefaultRootState
684
- > (
685
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
686
- mapDispatchToProps : null | undefined ,
687
- mergeProps : null | undefined ,
688
- options : ConnectOptions < State , TStateProps , TOwnProps >
689
- ) : InferableComponentEnhancerWithProps < DispatchProp & TStateProps , TOwnProps >
690
-
691
- /* @public */
692
- function connect < TStateProps = { } , TDispatchProps = { } , TOwnProps = { } > (
693
- mapStateToProps : null | undefined ,
694
- mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps > ,
695
- mergeProps : null | undefined ,
696
- options : ConnectOptions < { } , TStateProps , TOwnProps >
697
- ) : InferableComponentEnhancerWithProps < TDispatchProps , TOwnProps >
698
-
699
- /* @public */
700
- function connect < TStateProps = { } , TDispatchProps = { } , TOwnProps = { } > (
701
- mapStateToProps : null | undefined ,
702
- mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
703
- mergeProps : null | undefined ,
704
- options : ConnectOptions < { } , TStateProps , TOwnProps >
705
- ) : InferableComponentEnhancerWithProps < ResolveThunks < TDispatchProps > , TOwnProps >
706
-
707
- /* @public */
708
- function connect <
709
- TStateProps = { } ,
710
- TDispatchProps = { } ,
711
- TOwnProps = { } ,
712
- State = DefaultRootState
713
- > (
714
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
715
- mapDispatchToProps : MapDispatchToPropsNonObject < TDispatchProps , TOwnProps > ,
716
- mergeProps : null | undefined ,
717
- options : ConnectOptions < State , TStateProps , TOwnProps >
718
- ) : InferableComponentEnhancerWithProps < TStateProps & TDispatchProps , TOwnProps >
719
-
720
- /* @public */
721
- function connect <
722
- TStateProps = { } ,
723
- TDispatchProps = { } ,
724
- TOwnProps = { } ,
725
- State = DefaultRootState
726
- > (
727
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
728
- mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
729
- mergeProps : null | undefined ,
730
- options : ConnectOptions < State , TStateProps , TOwnProps >
731
- ) : InferableComponentEnhancerWithProps <
732
- TStateProps & ResolveThunks < TDispatchProps > ,
733
- TOwnProps
734
- >
735
-
736
- /* @public */
737
- function connect <
738
- TStateProps = { } ,
739
- TDispatchProps = { } ,
740
- TOwnProps = { } ,
741
- TMergedProps = { } ,
742
- State = DefaultRootState
743
- > (
744
- mapStateToProps : MapStateToPropsParam < TStateProps , TOwnProps , State > ,
745
- mapDispatchToProps : MapDispatchToPropsParam < TDispatchProps , TOwnProps > ,
746
- mergeProps : MergeProps < TStateProps , TDispatchProps , TOwnProps , TMergedProps > ,
747
- options ?: ConnectOptions < State , TStateProps , TOwnProps , TMergedProps >
748
- ) : InferableComponentEnhancerWithProps < TMergedProps , TOwnProps >
749
-
750
- /**
751
- * Connects a React component to a Redux store.
752
- *
753
- * - Without arguments, just wraps the component, without changing the behavior / props
754
- *
755
- * - If 2 params are passed (3rd param, mergeProps, is skipped), default behavior
756
- * is to override ownProps (as stated in the docs), so what remains is everything that's
757
- * not a state or dispatch prop
758
- *
759
- * - When 3rd param is passed, we don't know if ownProps propagate and whether they
760
- * should be valid component props, because it depends on mergeProps implementation.
761
- * As such, it is the user's responsibility to extend ownProps interface from state or
762
- * dispatch props or both when applicable
763
- *
764
- * @param mapStateToProps A function that extracts values from state
765
- * @param mapDispatchToProps Setup for dispatching actions
766
- * @param mergeProps Optional callback to merge state and dispatch props together
767
- * @param options Options for configuring the connection
768
- *
769
- */
770
- function connect (
771
- mapStateToProps ?: unknown ,
772
- mapDispatchToProps ?: unknown ,
773
- mergeProps ?: unknown ,
774
- {
775
- pure = true ,
776
- areStatesEqual = strictEqual ,
777
- areOwnPropsEqual = shallowEqual ,
778
- areStatePropsEqual = shallowEqual ,
779
- areMergedPropsEqual = shallowEqual ,
780
- ...extraOptions
781
- } : ConnectOptions < unknown , unknown , unknown , unknown > = { }
782
- ) : unknown {
783
- const initMapStateToProps = match (
784
- mapStateToProps ,
785
- // @ts -ignore
786
- defaultMapStateToPropsFactories ,
787
- 'mapStateToProps'
788
- )
789
- const initMapDispatchToProps = match (
790
- mapDispatchToProps ,
791
- // @ts -ignore
792
- defaultMapDispatchToPropsFactories ,
793
- 'mapDispatchToProps'
794
- )
795
- const initMergeProps = match (
796
- mergeProps ,
797
- // @ts -ignore
798
- defaultMergePropsFactories ,
799
- 'mergeProps'
800
- )
801
-
802
- return connectAdvanced (
803
- defaultSelectorFactory as SelectorFactory < any , any , any , any > ,
804
- {
805
- // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes
806
- shouldHandleStateChanges : Boolean ( mapStateToProps ) ,
807
-
808
- // passed through to selectorFactory
809
- initMapStateToProps,
810
- initMapDispatchToProps,
811
- initMergeProps,
812
- pure,
813
- areStatesEqual,
814
- areOwnPropsEqual,
815
- areStatePropsEqual,
816
- areMergedPropsEqual,
817
-
818
- // any extra options args can override defaults of connect or connectAdvanced
819
- ...extraOptions ,
820
- }
821
- )
822
- }
823
-
824
781
export default connect
0 commit comments