nytimes / react-tracking

🎯 Declarative tracking for React apps.
https://open.nytimes.com/introducing-react-tracking-declarative-tracking-for-react-apps-2c76706bb79a
Other
1.88k stars 123 forks source link

Feature proposal: server-side collection of trackingData #145

Open bwhitty opened 4 years ago

bwhitty commented 4 years ago

Hello! First of all, fantastic package. The Context-based hierarchical collection and merging of data is brilliant, and solves so many problems at once. This package is fantastic.

Let me know about your feelings on a feature like this, and I can get working on an implementation if it seems reasonable.

Proposal

I would like to gauge interest in allowing a new feature: server-side rendering support for collecting trackingData.

I have built this into a fully functional private implementation which involves wrapping the track HOC, but believe this can be vastly simplified if it was built directly into react-tracking's HOC.

API

The gist of the API looks like react-helmet, react-router, etc, in that it would work by shipping a new React Context provider which allows the user to pass an object on which all tracking data can be collected:

// my-server-renderer.js
import { ServerTrackingDataProvider } from 'react-tracking';

const trackingContext = {};

const html = renderToString(
  <ServerTrackingDataProvider serverContext={analyticsContext}>
    <App />
  </ServerTrackingDataProvider>
);

trackingContext.trackingData would now be equal to exactly the deepmerge'd result of all track(myTrackingData) which happened in that server rendering pass.

This would be implemented by retrieving the server context object and doing the same deepmerge logic as the existing HOC is doing internally:

const serverTrackingContext = useContext(ServerTrackingContext);

serverTrackingContext.trackingData = merge(
  serverTrackingContext.trackingData,
  getOwnTrackingData()
);

This would allow a user to either send tracking events server-side using some custom tracking API, or serialize it and send it to the client for out-of-band (outside of React) tracking calls.

Backwards compatible, opt-in

Using https://reactjs.org/docs/context.html#reactcreatecontext Context defaultValue, we can add logic to completely skip all of the logic if the value is false internally. This would make using the ServerTrackingDataProvider completely opt-in and backwards compatible.

const ServerTrackingContext = createContext(false);

Then, in https://github.com/nytimes/react-tracking/blob/ee390cd25445451e50f656241698ad564a4ccc85/src/withTrackingComponentDecorator.js#L23 we can then do something like:

const serverTrackingContext = useContext(ServerTrackingContext);

if (serverTrackingContext !== false) {
  // do merge logic here
}
tizmagik commented 4 years ago

Hello! First of all, fantastic package. The Context-based hierarchical collection and merging of data is brilliant, and solves so many problems at once. This package is fantastic.

First, thank you for the kind words, it's very much appreciated! 😁

Let me know about your feelings on a feature like this, and I can get working on an implementation if it seems reasonable.

Thanks for writing up an issue (before a PR), that's very helpful. I'd like to get a deeper understanding of the use case. E.g. why exactly do you want to do this on the server vs on the client? What specifically are you looking for when tracking server renderings?

In terms of supporting this in react-tracking, we don't have a use case for it at NYT but I'd be open to adding support if it (as you alluded to):

Also, if you can, I'd love to take a look at how you've currently implemented this by wrapping the track HoC, that might give me a better understanding of what's involved.

bwhitty commented 4 years ago

Thanks for getting back! Sounds good, I’ll write up the use case more deeply, and also show the current implementation.