You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

105 lines
3.4 KiB

  1. import connectAdvanced from '../components/connectAdvanced'
  2. import shallowEqual from '../utils/shallowEqual'
  3. import defaultMapDispatchToPropsFactories from './mapDispatchToProps'
  4. import defaultMapStateToPropsFactories from './mapStateToProps'
  5. import defaultMergePropsFactories from './mergeProps'
  6. import defaultSelectorFactory from './selectorFactory'
  7. /*
  8. connect is a facade over connectAdvanced. It turns its args into a compatible
  9. selectorFactory, which has the signature:
  10. (dispatch, options) => (nextState, nextOwnProps) => nextFinalProps
  11. connect passes its args to connectAdvanced as options, which will in turn pass them to
  12. selectorFactory each time a Connect component instance is instantiated or hot reloaded.
  13. selectorFactory returns a final props selector from its mapStateToProps,
  14. mapStateToPropsFactories, mapDispatchToProps, mapDispatchToPropsFactories, mergeProps,
  15. mergePropsFactories, and pure args.
  16. The resulting final props selector is called by the Connect component instance whenever
  17. it receives new props or store state.
  18. */
  19. function match(arg, factories, name) {
  20. for (let i = factories.length - 1; i >= 0; i--) {
  21. const result = factories[i](arg)
  22. if (result) return result
  23. }
  24. return (dispatch, options) => {
  25. throw new Error(
  26. `Invalid value of type ${typeof arg} for ${name} argument when connecting component ${
  27. options.wrappedComponentName
  28. }.`
  29. )
  30. }
  31. }
  32. function strictEqual(a, b) {
  33. return a === b
  34. }
  35. // createConnect with default args builds the 'official' connect behavior. Calling it with
  36. // different options opens up some testing and extensibility scenarios
  37. export function createConnect({
  38. connectHOC = connectAdvanced,
  39. mapStateToPropsFactories = defaultMapStateToPropsFactories,
  40. mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
  41. mergePropsFactories = defaultMergePropsFactories,
  42. selectorFactory = defaultSelectorFactory
  43. } = {}) {
  44. return function connect(
  45. mapStateToProps,
  46. mapDispatchToProps,
  47. mergeProps,
  48. {
  49. pure = true,
  50. areStatesEqual = strictEqual,
  51. areOwnPropsEqual = shallowEqual,
  52. areStatePropsEqual = shallowEqual,
  53. areMergedPropsEqual = shallowEqual,
  54. ...extraOptions
  55. } = {}
  56. ) {
  57. const initMapStateToProps = match(
  58. mapStateToProps,
  59. mapStateToPropsFactories,
  60. 'mapStateToProps'
  61. )
  62. const initMapDispatchToProps = match(
  63. mapDispatchToProps,
  64. mapDispatchToPropsFactories,
  65. 'mapDispatchToProps'
  66. )
  67. const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
  68. return connectHOC(selectorFactory, {
  69. // used in error messages
  70. methodName: 'connect',
  71. // used to compute Connect's displayName from the wrapped component's displayName.
  72. getDisplayName: name => `Connect(${name})`,
  73. // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes
  74. shouldHandleStateChanges: Boolean(mapStateToProps),
  75. // passed through to selectorFactory
  76. initMapStateToProps,
  77. initMapDispatchToProps,
  78. initMergeProps,
  79. pure,
  80. areStatesEqual,
  81. areOwnPropsEqual,
  82. areStatePropsEqual,
  83. areMergedPropsEqual,
  84. // any extra options args can override defaults of connect or connectAdvanced
  85. ...extraOptions
  86. })
  87. }
  88. }
  89. export default /*#__PURE__*/ createConnect()