Skip to content

Commit cb0fe9a

Browse files
authored
Merge pull request #20 from nytm/dispatchonmount-function
dispatchOnMount as a function
2 parents 00ff78e + e85e6e2 commit cb0fe9a

5 files changed

+56
-14
lines changed

README.md

+25-6
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99
## Installation
1010

1111
```
12-
npm install --save nytm/nyt-react-tracking#v2.0.0
12+
npm install --save nytm/nyt-react-tracking#v2.1.0
1313
```
1414

15-
(Or whatever is [latest](https://github.com/nytm/nyt-react-tracking/releases), it was 2.0.0 as of this writing)
15+
(Or whatever is the [latest version](https://github.com/nytm/nyt-react-tracking/releases))
1616

1717
## Usage
18-
@track() expects two arguments, `trackingData` and `options`.
18+
`@track()` expects two arguments, `trackingData` and `options`.
1919
- `trackingData` represents the data to be tracked
2020
- `options` is an optional object that accepts two properties:
2121
- `dispatch`, which is a function to use instead of the default CustomEvent dispatch behavior. See the section on custom `dispatch()` later in this document.
22-
- `dispatchOnMount`, when set to `true`, dispatches the tracking data when the component mounts to the DOM.
22+
- `dispatchOnMount`, when set to `true`, dispatches the tracking data when the component mounts to the DOM. When provided as a function will be called on componentDidMount with all of the tracking context data as the only argument.
2323

2424
`nyt-react-tracking` is best used as a `@decorator()` using the [babel decorators plugin](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy).
2525

@@ -94,9 +94,11 @@ NOTE: It is recommended to do this on some top-level component so that you only
9494

9595
### When to use `options.dispatchOnMount`
9696

97-
To dispatch tracking data when a component mounts, you can pass in `{ dispatchOnMount: true }` as the second parameter to `@track()`. This is useful for dispatching tracking data on "Page" components, for example.
97+
You can pass in a second parameter to `@track`, `options.dispatchOnMount`. There are two valid types for this, as a boolean or as a function. The use of the two is explained in the next sections:
98+
99+
#### Using `options.dispatchOnMount` as a boolean
98100

99-
For example:
101+
To dispatch tracking data when a component mounts, you can pass in `{ dispatchOnMount: true }` as the second parameter to `@track()`. This is useful for dispatching tracking data on "Page" components, for example.
100102

101103
```js
102104
@track({ page: 'FooPage' }, { dispatchOnMount: true })
@@ -115,6 +117,23 @@ Of course, you could have achieved this same behavior by just decorating the `co
115117

116118
_Note: this is only in affect when decorating a Class or stateless functional component. It is not necessary when decorating class methods since any invocations of those methods will immediately dispatch the tracking data, as expected._
117119

120+
#### Using `options.dispatchOnMount` as a function
121+
122+
If you pass in a function, the function will be called with all of the tracking data from the app's context when the component mounts. The return value of this function will be dispatched in `componentDidMount()`. You do not have to use the app's context data, so you can explicitly define the entire shape of the tracking data to dispatch for a "page view" event, for example.
123+
124+
```js
125+
@track({ page: 'FooPage' }, { dispatchOnMount: (contextData) => ({ event: 'pageDataReady' }) })
126+
class FooPage extends Component { ... }
127+
```
128+
129+
Will dispatch the following data (notice, the `contextData` was ignored in the function we defined):
130+
131+
```
132+
{
133+
event: 'pageDataReady'
134+
}
135+
```
136+
118137
### Advanced Usage
119138

120139
You can also pass a function as an argument instead of an object literal, which allows for some advanced usage scenarios such as when your tracking data is a function of some runtime values, like so:

build/withTrackingComponentDecorator.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,12 @@ function withTrackingComponentDecorator() {
7878
args[_key] = arguments[_key];
7979
}
8080

81-
return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, (_ref2 = WithTracking.__proto__ || (0, _getPrototypeOf2.default)(WithTracking)).call.apply(_ref2, [this].concat(args))), _this), _this.trackEvent = function (data) {
81+
return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, (_ref2 = WithTracking.__proto__ || (0, _getPrototypeOf2.default)(WithTracking)).call.apply(_ref2, [this].concat(args))), _this), _this.getTrackingData = function (data) {
82+
return (0, _lodash2.default)({}, _this.getChildContext().tracking.data, data);
83+
}, _this.trackEvent = function (data) {
8284
_this.getTrackingDispatcher()(
8385
// deep-merge tracking data from context and tracking data passed in here
84-
(0, _lodash2.default)({}, _this.getChildContext().tracking.data, data));
86+
_this.getTrackingData(data));
8587
}, _temp), (0, _possibleConstructorReturn3.default)(_this, _ret);
8688
}
8789

@@ -110,6 +112,10 @@ function withTrackingComponentDecorator() {
110112
if (dispatchOnMount === true) {
111113
this.trackEvent();
112114
}
115+
116+
if (typeof dispatchOnMount === 'function') {
117+
this.getTrackingDispatcher()(dispatchOnMount(this.getTrackingData()));
118+
}
113119
}
114120
}, {
115121
key: 'render',

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nyt-react-tracking",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "Declarative tracking for React apps.",
55
"author": "The New York Times",
66
"contributors": [

src/__tests__/e2e.test.js

+15
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,19 @@ describe('e2e', () => {
109109
},
110110
});
111111
});
112+
113+
it('will call dispatchOnMount as a function', () => {
114+
const testDispatchOnMount = { test: true };
115+
const dispatchOnMount = jest.fn(() => ({ dom: true }));
116+
117+
@track(testDispatchOnMount, { dispatch, dispatchOnMount })
118+
class TestComponent extends React.Component {
119+
render() { return null; }
120+
}
121+
122+
mount(<TestComponent />);
123+
124+
expect(dispatchOnMount).toHaveBeenCalledWith(testDispatchOnMount);
125+
expect(dispatch).toHaveBeenCalledWith({ dom: true });
126+
});
112127
});

src/withTrackingComponentDecorator.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,12 @@ export default function withTrackingComponentDecorator(
2323
tracking: TrackingPropType,
2424
};
2525

26+
getTrackingData = data => merge({}, this.getChildContext().tracking.data, data)
27+
2628
trackEvent = (data) => {
2729
this.getTrackingDispatcher()(
2830
// deep-merge tracking data from context and tracking data passed in here
29-
merge(
30-
{},
31-
this.getChildContext().tracking.data,
32-
data
33-
)
31+
this.getTrackingData(data)
3432
);
3533
}
3634

@@ -57,6 +55,10 @@ export default function withTrackingComponentDecorator(
5755
if (dispatchOnMount === true) {
5856
this.trackEvent();
5957
}
58+
59+
if (typeof dispatchOnMount === 'function') {
60+
this.getTrackingDispatcher()(dispatchOnMount(this.getTrackingData()));
61+
}
6062
}
6163

6264
render() {

0 commit comments

Comments
 (0)