25
Tracking in React Apps
if you are interested in the application code more than the tracking implementation. Leave reaction to this post, I'll consider making another post to explain it.
Nowadays, tracking user experience is a must for most application, by collecting the tracked data from user we can develop, fixing or improve our feature (especially UX).
Based on my experience tracking can be differ into 2 category :
product / marketing
: this tracking goals is to keep track and evaluate marketing approaches (FB ads, google ads, instagram link, etc), and help product team to evaluate UXerror
: this tracking purpose is to notify developer about the error that occur in production before customer making any complain.Let's see the implementation in react code
To implements tracking we need to at least having an application. I have create a base project at:
What is the app functionality ?
Home
and Top News
refresh
news functionality
What are we going to track ?
go to source
button, we want to evaluate whether user usually go to tops news
tab or not, so the Data expected looks like :
{
eventName: 'click_go_to_source',
page: 'Home / TopNews'
}
refresh feed
button, we want to evaluate whether user click refresh feed
button or not so the data expected looks like :
{
eventName: 'refresh_feed',
page: 'Home / TopNews'
}
fetching data
, we want to track every error occur when fetching data. Data expect to looks like :
{
eventName: 'error_fetch',
page: 'Home / TopNews',
errorReason: stringify error object
}
Basically it's just calling 3rd party sdk / api for event tracking or logging on every click handler or error catch
In this code example we will use Mocked
DataDog
for our error tracking and MixPanel
for our click tracking. The code implementation can be seen in link.
Click Go To Source Track
every time the user click
every time the user click
go to source
this code will send over the data to mock MixPanel
.// ArticleCard.js
...
// line 7
const handleClick = () => {
const eventName = "click_go_to_source";
const unique_id = uuid();
MixPanel.track(eventName, unique_id, {
page,
});
...
};
....
Click Refresh Feed Track
every time the user click
every time the user click
refresh feed
this code will send over the data to mock MixPanel
.// Home.js or TopNews.js
...
// line 26
const onRefreshClick = () => {
const eventName = "refresh_feed";
const unique_id = uuid();
MixPanel.track(eventName, unique_id, {
page,
});
...
};
....
Fetch News error Track
every time our fetch to news from newsapi failed, this code will send over the
every time our fetch to news from newsapi failed, this code will send over the
fetch_error
data to mock DDlog
.// Home.js or TopNews.js
...
// line 15
onError: (err) => {
const eventName = "error_fetch";
DDlog.error(eventName, {
page,
errorReason: JSON.stringify(err, null, 4),
});
},
....
It seems everything to work fine ๐ค, yep that's what i thought, until some changes was needed because of new feature or 3rd Party tracking platform commercial issue / fees.
Imagine that we already put 100+ tracker over 10 screens, then we need to :
MixPanel
to Heap
. we need to manually refactor all of our MixPanel
tracking code 1-by-1 ๐ตโ๐ซ. Gratefully, i encounter this problem when my tracker was still less than 20 ๐ฎโ๐จ. But there is a question pop up on my mind, do i need to change the code one-by-one every time there is commercial issue or new feature that affect current tracking ?
That's what lead me to
react-tracking
by NYT, a React specific tracking library. it helps to :Let's see the code implementation link.
We create
ReactTrackingInitializer
HOC (High Order Component) to be our parent / root tracking wrapper.const ReactTrackingInitializer = ({ children }) => {
const { Track } = useTracking(
{
// this is where the initialize data put
trackVersion: "1.0.0",
},
{
dispatch: (trackedData) => {
console.log("dispatchData", trackedData);
}
);
return <Track>{children}</Track>;
};
useTracking
is a hooks version to implementing react-tracking
which suitable for functional component, find out more on their docs if you still implementing class component.useTracking
takes 2 params:dispatch
,dispatchOnMount
,process
, and fowardRef
more detail check react-tracking
useTracking
will return object with 3 properties:trackEvent
: a function to send data to be process at process
, then dispatch
.getTrackingData
: a function that return current initial data in our tracker.Track
: a HOC that wrapped a child component to give scope to it's initial data, process
and dispatch
logic. which later can be triggered using trackEvent
From the reference we can implements our 3rd Party logic at
dispatch
option. so it will looks like this :...
dispatch: (trackedData) => {
console.log("dispatchData", trackedData);
const { eventName, ...restOfData } = trackedData.data;
switch (trackedData.type) {
case "product":
const unique_id = uuid();
MixPanel.track(eventName, unique_id, restOfData);
break;
case "error":
DDlog.error(eventName, restOfData);
break;
default:
break;
}
},
...
It looks a lot like
redux
reducers. Now you might ask there must be a dispatch mechanism to like redux, where is it ? checkout the code at Home.js
line 25 - 33const { trackEvent, Track } = useTracking({
data: { page: "HOME" },
});
const onRefreshClick = () => {
trackEvent({ type: "product", data: { eventName: "refresh_feed" } });
refetch();
};
the
trackEvent
will send over the data below to our dispatch
function.{
type: "product",
data: {
eventName: "refresh_feed",
page: "HOME"
}
trackVersion: "1.0.0"
}
Wait, Where did
trackVersion: "1.0.0"
and page: "HOME"
came from ๐ ? react tracking perform a merge operation on data we sent and initial data provided. in this case :{
type: "product",
data: {
eventName: "refresh_feed"
}
}
Home.js
useTracking :
{
data: {
page: "HOME"
}
}
ReactTrackingInitializer
useTracking:
{
trackVersion: "1.0.0"
}
We already utilize
react-tracking
๐๐๐, Just Note that:<Track></Track>
at root level (prefer to wrap )<Track></Track>
. that why we wrapped <ArticleCard>
in Home.js
line 57 - 63, so it get the initial value from Home.js
useTracking, otherwise it will only have initial value of ReactTrackingInitializer.js
.Now back to the problem, let say we need to:
just see the difference between branch
rtracking
and rtracking-solution
.
Changes need
#1
peterchu999
posted on
Changes need to solve the problem statement:
- change MixPanel to Heap
- add user data, because we have add login feature
and compare it to the difference between branch
direct
and direct-solution`.
Changes Need -> Direct Solution
#2
peterchu999
posted on
Changes need to solve the problem statement:
change MixPanel to Heap add user data, because we have add login feature
It will more work to be done when using 3rdParty Sdk / API directly, Imagine we have 10+ MixPanel tracker, it will cost a lot of time.
React Tracking Help us to centralize the tracking logic so if there are any changes needed we can just refactor our dispatch function.
Thanks for reading, leave any comment below ๐
nytimes
/
react-tracking
๐ฏ Declarative tracking for React apps.
25