When development of blip in its current form as a React application began in late 2013 and the beginning of 2014, React Router did not yet exist, at least not as a well-supported and widely-used client-side routing solution for React applications.
Originally blip used director, a framework-agnostic (as well as isomorphic) JavaScript library for routing. This didn't "play" terribly well with React, and the routing code was complex, difficult to understand, difficult to debug, etc. By far the most difficult thing was understanding where the source of truth was regarding application state/location: in the route (URL) or in the app's top-level component (React) state. (We had a doozy of an <App/>
component back then at the top level that was 1000s of lines long (😱), and app state was basically all contained in the state of this component, except for the stuff that director managed, if it was truly the source of truth for that state.)
We ripped apart the old <App/>
component and refactored to bring in React Router as our routing solution in late 2015. Routes are defined in app/routes.js.
One of our goals for the incremental rewrite of Tidepool's data visualization code (from tideline to viz) is to enable "deep linking" in the data visualization(s) so that a user can bookmark or copy and share a URL and anyone who has that URL (and permissions to view the relevant PwD's data) will see essentially the same data visualization that the original user saw.
The vast majority of the data visualization state, including which of the five "views" the user is on (Basics, Daily, BG Log, Trends, or Device Settings) is currently encapsulated inside the <PatientData/>
component as its React-internal state
.
As we're rewriting visualization code, we're adding new state—i.e., that didn't exist before, such as state belonging to the new CGM version of the Trends view and the state of which basal schedules or settings profiles are open or collapsed on the Device Settings view—to blip's redux-controlled state by way of a vizReducer
as one of the exports from the new viz repo. By including this reducer in our composed root reducer for blip, we ensure that blip's state updates in response to any of the action creators fired in viz components (or in blip, where we import action creator functions themselves or component from viz to be rendered in blip).
As we move more and more visualization code into viz and especially as we move functionality controlling some aspects of the visualization state (such as which view is active) from blip into viz, we'll have to plan for the eventual goal of deep-linking or, in other words, think carefully about where the source of truth for certain state should live.
Take the active view, for example, which in the current <PatientData/>
state, we track as chartType
. This state will definitely need to be part of the URL as the first step along the road to "deep linking": we want URLs of the form /patients/:id/data/basics
and /patients/:id/data/daily
instead of the current /patients/:id/data
for all views. In order to avoid duplication of state1 between the routing
branch of blip's state (updated via the routeReducer
which is an export from the react-router-redux package in a fashion directly parallel2 to our export of vizReducer
from the @tidepool/viz package) and the viz
branch of state controlled by the vizReducer
, we'll need to use a different strategy—that is, not the current vizReducer
strategy—to update the chartType
state so that this state is properly "owned" by the routeReducer
.
There may be several ways of solving the problem of affecting routing
state from viz, which has no direct access to blip's router (and nor should it). A couple to consider are:
- viz dispatches actions representing state changes that are reflected in the URL (such as the active view) as per usual in a Redux implementation, but no state changes are defined for these action types in the exported
vizReducer
; instead, blip intercepts all such actions (according to theirtype
) with a middleware and dispatches arouteActions.push
action to update therouting
state - viz includes React Router as a dependency and the top-level component exported to blip requires a set of
href
s as props to populate its React Router<Link/>
s
Footnotes
-
As a known issue/remaining tech debt from the introduction of React Router and Redux into the blip codebase, we currently have some duplication of information across the
routing
andblip
branches of blip's state tree. A good example is the user ID hash of the PwD whose data is in view on the/patients/:id/data
path currently used for all data views; this ID is part of therouting
state as the:id
param in the path, but it is also set as thecurrentPatientInViewId
in theblip
branch of the state tree upon successful fetching of the PwD's profile. ↩ -
And, in fact, one of the inspirations for the way we structured the @tidepool/viz package along with the redux-form package. ↩