1
1
import {
2
2
DependencyMap ,
3
3
DependencyMapProps ,
4
- GetProps ,
5
4
ConnectedComponentType ,
6
5
calculateInitial ,
7
- calculate ,
6
+ calculateForDispatch ,
7
+ makeDependencyIndex ,
8
+ DependencyIndexEntry ,
8
9
} from './DependencyMap' ;
9
10
import { Dispatcher } from 'flux' ;
10
- import { makeDisplayName } from './BuildComponent' ;
11
+ import { makeDisplayName , focuser } from './BuildComponent' ;
11
12
import { dependencyPropTypes } from '../dependencies/DependencyMap' ;
12
13
import { get as getDispatcherInstance } from '../dispatcher/DispatcherInstance' ;
13
14
import { enforceDispatcher } from '../dispatcher/DispatcherInterface' ;
14
15
import * as React from 'react' ;
15
- import { ComponentType , forwardRef , RefObject , useRef , useState } from 'react' ;
16
+ import { ComponentType , RefObject , useRef } from 'react' ;
16
17
import hoistStatics from 'hoist-non-react-statics' ;
17
- import { _useDispatchSubscription } from './useStoreDependency' ;
18
- import { shallowEqual , oMap } from '../utils/ObjectUtils' ;
18
+ import { handleDispatch } from './Dispatch' ;
19
19
20
20
export function useCurrent < ValueType > ( value : ValueType ) : RefObject < ValueType > {
21
21
const ref = useRef ( value ) ;
@@ -29,56 +29,77 @@ export default function connect<Deps extends DependencyMap>(
29
29
) {
30
30
enforceDispatcher ( dispatcher ) ;
31
31
32
+ const dependencyIndex = makeDependencyIndex ( dependencies ) ;
33
+
32
34
return function connector <
33
35
C extends any ,
34
36
Props extends DependencyMapProps < Deps >
35
37
> ( BaseComponent : ComponentType < Props > ) : ConnectedComponentType < Props , C > {
36
- const ConnectedComponent : ConnectedComponentType < Props & C , C > = forwardRef (
37
- ( props : GetProps < C > , ref ) => {
38
- enforceDispatcher ( dispatcher ) ;
38
+ class ConnectedComponent extends React . Component < Props , any > {
39
+ static defaultProps ?: Partial < Props > = BaseComponent . defaultProps ;
40
+ static dependencies : Deps = dependencies ;
41
+ static displayName = makeDisplayName ( 'Connected' , BaseComponent ) ;
42
+ static propTypes : any = dependencyPropTypes (
43
+ dependencies ,
44
+ // eslint-disable-next-line react-app/react/forbid-foreign-prop-types
45
+ BaseComponent . propTypes
46
+ ) ;
47
+ static WrappedComponent : ComponentType < Props > = BaseComponent ;
39
48
40
- const [ dependencyValue , setDependencyValue ] = useState (
41
- ( ) => calculateInitial ( dependencies , props , { } ) || { }
42
- ) ;
49
+ static getDerivedStateFromProps ( props : unknown , state : unknown ) {
50
+ return calculateInitial ( dependencies , props , state ) ;
51
+ }
43
52
44
- const currProps = useCurrent ( props ) ;
53
+ dispatchToken ?: string ;
54
+ state : any = { } ;
55
+ wrappedInstance ?: HTMLElement = null ;
45
56
46
- _useDispatchSubscription (
47
- dependencies ,
48
- currProps ,
49
- dispatcher ,
50
- dependencyValue ,
51
- setDependencyValue
52
- ) ;
57
+ constructor ( props : Props ) {
58
+ super ( props ) ;
59
+ if ( dispatcher ) {
60
+ this . dispatchToken = dispatcher . register (
61
+ handleDispatch . bind (
62
+ null ,
63
+ dispatcher ,
64
+ dependencyIndex ,
65
+ this . handleDispatch . bind ( this )
66
+ )
67
+ ) ;
68
+ }
69
+ this . state = calculateInitial ( dependencies , this . props , { } ) ;
70
+ }
53
71
54
- const newValue = oMap ( dependencies , dep =>
55
- calculate ( dep , props , dependencyValue )
56
- ) ;
57
- if (
58
- Object . keys ( newValue )
59
- . map ( k => shallowEqual ( newValue [ k ] , dependencyValue [ k ] ) )
60
- . some ( el => el === false )
61
- ) {
62
- setDependencyValue ( newValue as typeof dependencyValue ) ;
72
+ componentWillUnmount ( ) {
73
+ const dispatchToken = this . dispatchToken ;
74
+ if ( dispatcher && dispatchToken ) {
75
+ this . dispatchToken = null ;
76
+ dispatcher . unregister ( dispatchToken ) ;
63
77
}
78
+ }
64
79
65
- // TypeScript really doesn't like how I'm typing the output here
66
- // @ts -ignore
67
- return < BaseComponent { ...props } { ...dependencyValue } ref = { ref } /> ;
80
+ handleDispatch ( entry : DependencyIndexEntry ) {
81
+ this . setState (
82
+ calculateForDispatch ( dependencies , entry , this . props , this . state )
83
+ ) ;
68
84
}
69
- ) ;
70
85
71
- ConnectedComponent . defaultProps = BaseComponent . defaultProps ;
72
- ConnectedComponent . dependencies = dependencies as Deps ;
73
- ConnectedComponent . displayName = makeDisplayName (
74
- 'Connected' ,
75
- BaseComponent
76
- ) ;
77
- ConnectedComponent . propTypes = dependencyPropTypes (
78
- dependencies ,
79
- BaseComponent . propTypes
80
- ) ;
81
- ConnectedComponent . WrappedComponent = BaseComponent ;
86
+ focus =
87
+ typeof BaseComponent . prototype . focus === 'function'
88
+ ? ( ...args : any [ ] ) => focuser ( this , ...args )
89
+ : undefined ;
90
+
91
+ setWrappedInstance = ( ref : HTMLElement ) => {
92
+ this . wrappedInstance = ref ;
93
+ } ;
94
+
95
+ render ( ) {
96
+ const refProps =
97
+ typeof BaseComponent === 'function'
98
+ ? { }
99
+ : { ref : this . setWrappedInstance } ;
100
+ return < BaseComponent { ...this . props } { ...this . state } { ...refProps } /> ;
101
+ }
102
+ }
82
103
83
104
return hoistStatics ( ConnectedComponent , BaseComponent ) ;
84
105
} ;
0 commit comments