Category:

React drives front-end development at Hootsuite.  It is a modern, powerful javascript framework that allows the view to be easily rendered as a function of the state of the application.  Components can pull information about state from the props their parent passes them, from the global application state (enabled typically with a flux framework), or remain stateless.  We’ll take a look at how we solved a limitation with Google Analytics tracking in a React + flux context.

The Problem

The message composition flow allows for the application of link settings on URLs for both scheduled and instant posts.  URLs can be shortened (i.e. bit.ly or ow.ly) and tracked with Google Analytics, Adobe Analytics, or any other custom web analytics tracker.  This is facilitated by passing utm parameters to the URL, and allows the user to track traffic sources and other data to analyze the effectiveness of advertising and marketing campaigns.

However, Google Analytics only recognizes five parameters:

  • utm_source
  • utm_medium
  • utm_campaign
  • utm_term
  • utm_content
and only officially supports one value per parameter.  This limits the flexibility and customizability of tracking – for example, when requiring multiple values for a campaign or content.

The solution is to concatenate additional values onto each parameter in the query string, separated by a user-specified character delimiter (defaulted to an underscore).  While simple, it enables filtering and other functions using these additional values within the Google Analytics dashboard.  To implement this change, the model representing link settings needs to be updated to map multiple values to a parameter, but existing link settings will necessitate that the old model be supported alongside the new one.

Updating the Model

Link tracking parameters are stored as an array of objects, each representing a parameter.  In the legacy model, each parameter object is associated with a single value.  (If you’re curious about what those fields refer to, the type field indicates whether it is a manual or dynamic value, while the typeValue field distinguishes between different dynamic values.)

With the new model, each parameter object is mapped to an array of objects representing parameter values.  These parameter values retain their type and typeValue fields to accommodate dynamic and manual values.  For backwards compatibility with existing link settings, the parameter object is enumerated as a new “Compound” type.

Updating the code

To see why React is well-suited to our multiple value aspirations, we first have to get a sense of how React works.

React is designed with flux in mind, which entails uni-directional data flow.  And the converse is true too; while you could theoretically use a flux pattern with any other frontend framework, it is usually coupled with React.  The flux library we use at Hootsuite is flummox, but since its deprecation we have been transitioning to redux.

A user interaction with the view will trigger an action, which modifies the data in the store.  React will handle the store changes and automatically re-render the view with the modified data.  Data from any API calls are also typically saved to the store via actions.

Since the view follows directly from the state (stored in the store), this allows us to easily support the legacy model as well as the new model.  Instead of having to construct two components that handle each model separately, we can refactor the existing component to render different views depending on whether or not the state possesses certain properties – in this case, whether or not it contains compoundTrackers.  In addition, all the existing structures we have set up for the service calls and stores can be reused.  These are the pros of React, and enforce the concept of the view being a function of the state.

Here, we can see in the code that the rendering component has been updated to detect the new model.  If multiple values exist for a parameter, their input fields are rendered below each other.  If, instead, we are dealing with parameter(s) stored with the legacy model, it simply defaults to the else branch and renders as expected.

With this change, the creation UI is modified.  On the left is the view for customizing/creating a link setting without multiple values per parameter, and on the right is the same view modified to support parameter concatenation.

We also update the generated sample URL to reflect the additional parameters values concatenated.  This is an example of what a URL with link settings applied will ultimately look like.

Challenges and improvements

Because the view is designed to be driven by the model, a problem exists with legacy link settings.  Although they will maintain their existing functionality, they will not be able to support multiple values per parameter.  This is because they will still be represented by the old model, lacking the compoundTracker field.

While it would be easy to add a check for this in the code, the series of seemingly arbitrary if-else branches would pollute the readability of the code as well as affect the scalability of the component in the future.  An alternative would be to migrate existing link settings to the new model, but that would be slightly overkill for the task.

Final Thoughts

For this project, we elected to have the state exist in a store to make it globally accessible.  This is necessary since the link settings component exists in multiple contexts.  However, React gives you the flexibility to store state in different areas depending on the scale of the application and your needs.  For example, very specific or niche data can usually be stored directly in the state of the component itself.  A component could even be stateless and solely responsible for “dumb” rendering.

With React, we were able to easily extend link tracking functionality by updating the model and refactoring the link settings component.  In general, React is flexible enough to scale up or down – partly due to its coupling with flux, and partly due to modular component design being one of its central tenets.  Hopefully, this has given you a little more insight into how and why we use it at Hootsuite.

About the Author

Patrick is a full-stack developer co-op on the Plan and Create team at Hootsuite.  He is a 3rd year student at the University of Waterloo studying Computer Science.  His favourite superhero is Jean Grey.  Connect with him on LinkedIn.