Skip to content

Commit 13056c8

Browse files
authored
Merge pull request #93 from HubSpot/adam/revert-connect-to-class
revert connect to class component
2 parents 47de4e0 + 75d3aa8 commit 13056c8

File tree

1 file changed

+65
-44
lines changed

1 file changed

+65
-44
lines changed

src/dependencies/connect.tsx

+65-44
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import {
22
DependencyMap,
33
DependencyMapProps,
4-
GetProps,
54
ConnectedComponentType,
65
calculateInitial,
7-
calculate,
6+
calculateForDispatch,
7+
makeDependencyIndex,
8+
DependencyIndexEntry,
89
} from './DependencyMap';
910
import { Dispatcher } from 'flux';
10-
import { makeDisplayName } from './BuildComponent';
11+
import { makeDisplayName, focuser } from './BuildComponent';
1112
import { dependencyPropTypes } from '../dependencies/DependencyMap';
1213
import { get as getDispatcherInstance } from '../dispatcher/DispatcherInstance';
1314
import { enforceDispatcher } from '../dispatcher/DispatcherInterface';
1415
import * as React from 'react';
15-
import { ComponentType, forwardRef, RefObject, useRef, useState } from 'react';
16+
import { ComponentType, RefObject, useRef } from 'react';
1617
import hoistStatics from 'hoist-non-react-statics';
17-
import { _useDispatchSubscription } from './useStoreDependency';
18-
import { shallowEqual, oMap } from '../utils/ObjectUtils';
18+
import { handleDispatch } from './Dispatch';
1919

2020
export function useCurrent<ValueType>(value: ValueType): RefObject<ValueType> {
2121
const ref = useRef(value);
@@ -29,56 +29,77 @@ export default function connect<Deps extends DependencyMap>(
2929
) {
3030
enforceDispatcher(dispatcher);
3131

32+
const dependencyIndex = makeDependencyIndex(dependencies);
33+
3234
return function connector<
3335
C extends any,
3436
Props extends DependencyMapProps<Deps>
3537
>(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;
3948

40-
const [dependencyValue, setDependencyValue] = useState(
41-
() => calculateInitial(dependencies, props, {}) || {}
42-
);
49+
static getDerivedStateFromProps(props: unknown, state: unknown) {
50+
return calculateInitial(dependencies, props, state);
51+
}
4352

44-
const currProps = useCurrent(props);
53+
dispatchToken?: string;
54+
state: any = {};
55+
wrappedInstance?: HTMLElement = null;
4556

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+
}
5371

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);
6377
}
78+
}
6479

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+
);
6884
}
69-
);
7085

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+
}
82103

83104
return hoistStatics(ConnectedComponent, BaseComponent);
84105
};

0 commit comments

Comments
 (0)