-
Notifications
You must be signed in to change notification settings - Fork 124
/
withTrackingComponentDecorator.js
81 lines (69 loc) · 2.58 KB
/
withTrackingComponentDecorator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import PropTypes from 'prop-types';
import ReactTrackingContext from './ReactTrackingContext';
import useTrackingImpl from './useTrackingImpl';
export default function withTrackingComponentDecorator(
trackingData = {},
{ forwardRef = false, ...options } = {}
) {
return DecoratedComponent => {
const decoratedComponentName =
DecoratedComponent.displayName || DecoratedComponent.name || 'Component';
function WithTracking({ rtFwdRef, ...props }) {
const latestProps = useRef(props);
useEffect(() => {
// keep the latest props in a mutable ref object to avoid creating
// additional dependency that could cause unnecessary re-renders
// see https://reactjs.org/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often
latestProps.current = props;
});
const trackingDataFn = useCallback(
() =>
typeof trackingData === 'function'
? trackingData(latestProps.current)
: trackingData,
[]
);
const contextValue = useTrackingImpl(trackingDataFn, options);
const trackingProp = useMemo(
() => ({
trackEvent: contextValue.tracking.dispatch,
getTrackingData: contextValue.tracking.getTrackingData,
}),
[contextValue]
);
const propsToBePassed = useMemo(
() => (forwardRef ? { ...props, ref: rtFwdRef } : props),
[props, rtFwdRef]
);
return (
<ReactTrackingContext.Provider value={contextValue}>
{React.createElement(DecoratedComponent, {
...propsToBePassed,
tracking: trackingProp,
})}
</ReactTrackingContext.Provider>
);
}
if (forwardRef) {
const forwarded = React.forwardRef((props, ref) =>
React.createElement(WithTracking, { ...props, rtFwdRef: ref })
);
forwarded.displayName = `WithTracking(${decoratedComponentName})`;
hoistNonReactStatics(forwarded, DecoratedComponent);
return forwarded;
}
WithTracking.displayName = `WithTracking(${decoratedComponentName})`;
WithTracking.propTypes = {
rtFwdRef: PropTypes.oneOfType([
PropTypes.func,
// eslint-disable-next-line react/forbid-prop-types
PropTypes.shape({ current: PropTypes.any }),
]),
};
WithTracking.defaultProps = { rtFwdRef: undefined };
hoistNonReactStatics(WithTracking, DecoratedComponent);
return WithTracking;
};
}