My Experience with Adding React to a Legacy Application (with d3)
By: Robert Gutierrez
Tags: React Router, React, Legacy App Modernization, Legacy Application, D3js

Step 1: how do I add React to an existing application?

I had built small React apps for tutorials, online classes, etc., but they were all standalone. I had to figure out a way to keep the React workflow I was used to but somehow hook it into my existing web app. The React docs have a very nice section on how to add React into an existing web site, and this was crucial to getting me started. I actually used their transpiling shortcut with my personal web site, which allowed me to write a small component in JSX and transpile it into a vanilla JS file that I could include on my home page.

This was the key for hooking React into the Survey Portal. Initially, I wrote one test component and ended up with something similar to what’s show in the docs:

And it worked. I created an src directory at the project root and had the transpiler automatically watching it. Whenever I saved a change, it wrote to the JS file in my static directory, and everything was groovy.

But this worked well for one file, maybe a few. What about a whole React app?

Enter the next evolution in my transpiling journey: webpack. I could turn this idea up to eleven and build a whole React “mini app” within my src folder, then use webpack to transpile my JSX, include all my libraries, and minify the code into a single file that I could include with a <script> tag.

Now this ended up working out quite nicely.

Of course, there is a slight drawback to this approach. As we add more components and include more libraries, the size of the file increases. Currently, the minified size is up to 602kb. So, a bit large, but only slightly noticeable on the initial page load. Everything is butter smooth after that.

Step 2: how do I make my React app “addressable” from within my existing application?

This was another hiccup. Reports, as they have functioned before in the Survey Portal, were entities within the Datastore (the ndb library gives us an ORM-like interface where we can retrieve objects back from the Datastore). Each report has an ID, title, template (or “type” of report), and data in the form of JSON. When using the Survey Portal, each report is addressable by its id, and the request handler loads the object from the Datastore, picks the corresponding Jinja template, then passes the JSON data to the template for consumption.

Here’s a sample Report object, in JSON format:

Each report object is accessed through a route that looks like /reports/report/<report_id> , so I needed to load the React app at this route, but only for our new reports. Easy enough. Just make the template that’s rendered for this report type blank, with a single <div> for mounting the app, and the <script> tag for loading the app code. We pretty much end up with our example from step one.

The tricky part was getting react-router-dom to play nicely with our existing request router. I could have used HashRouter and skipped some headache but I wanted to use the new BrowserRouter which gave me pretty URLs and a history. I needed to attach these pretty relative URLs to the report URL from the web app so that everything appeared seamless.

To do this, I spit out the report URL to the browser as a global variable. There’s probably a better way to do it but this worked well enough for me. This became the basename for my BrowserRouter , and thus gave me my pretty URLs.