Integrate ReactJS into a legacy Dojo application

Because technology moves fast, it’s easy to feel left behind. An old version of a JavaScript library is making your application perform slowly. You spend most of your time patching old code. Your UI looks like it was created years ago, but you don’t have time to update it.

Our team recently faced all these challenges when our 10-year-old product was using an old version of the Dojo toolkit. To migrate to the latest version of Dojo, we needed to rewrite the whole code with an asynchronous model. Our solution also needed to improve performance and provide a rich UI experience that complies with the IBM Carbon theme.

After a lot of research, we decided to use React JS instead of upgrading to a new version of Dojo. This blog post introduces ReactJS, highlights the research we did when comparing ReactJS with other JavaScript languages, and explains how we integrated ReactJS with our current Dojo library.

Solution: Our goal was to develop new pages with ReactJS and integrate them into our existing legacy Dojo application. We also needed to create reusable components of React in order to implement a single-page application quickly and migrate our whole application page-by-page in the long run.

What is ReactJS?

React is a JavaScript library used to create rich web and mobile-based applications. The open-source, component-based library renders views of applications. It’s based on MVC (Model View Controller) architecture.

While choosing the next technology, we compared Dojo, Angular, Vue.js, and React. The following table shows you the features we evaluated.

Features Dojo ReactJS AngularJS VueJS
Framework Modular JavaScript library Easy reusable components,
high modularity,
Virtual DOM
MVC Virtual DOM
GitHub stars 61K 164K+ 70.9K 200K
Learning curve Medium Easy Steep–must master
TypeScript and MVC
Easy to learn
Minified size 598KB 6.5KB 252.2KB 63.3KB
Data binding Achieved through APIs Uni-directional Bi-directional Bi-directional
Used by MasterCard, ADP, Fortinet Facebook, Uber, Netflix Google, Wix, PayPal
Upwork
Alibaba, Gitlab,
Adobe, Grammarly

React.js offered us the features we needed most, including:

  • Easy to create dynamic applications
  • For better performance
  • Reusable components
  • Easy to learn
  • Unidirectional data flow
  • Dedicated tools for debugging
  • Virtual DOM rendering
  • Flux architecture
  • High market value

Highlights of integration

Our application contains different pages that render the navigation menu, main header, and content. In our new solution, we decided to add new pages with React on top of the existing Dojo base. Dojo still renders the navigation and main page, but the content pages use React. We made this choice because of our heavy dependency on the main header which was hard and slow to migrate.

Image shows master header and navigation

For our integration, we made a few key decisions. We decided to:

  1. Start with a simple, new feature.
  2. Identify the common components across our pages. For example, evaluate which pages have specific components like data tables, navigation bars, forms, search components to fetch backend data etc.
  3. Create reusable components like search filters to use across all pages.
  4. Create a parent page and integrate the components according to the requirements of the specific pages.
  5. Use inside-out portal development of common components like left and top navigations which are Dojo-based but can be rendered via a React application.
  6. Use the Carbon theme https://www.carbondesignsystem.com/ for the layout. Carbon is an open-source design system for products and digital experiences. The system uses the IBM Design Language as its foundation and consists of working code, design tools and resources, human interface guidelines, and a vibrant community of contributors.

Let’s look a little closer at specific integration components.

Masthead/Banner integration

From the start, our application’s masthead component was being used by other applications. So, we designed it in such a way that it could be integrated with applications.

We had exposed the masthead as a JavaScript which can we integrated with other web applications. This came very handy for us when we were developing with React. Without having to re-write the whole navigation code, we could directly start with the main content with masthead loading from Dojo and the contents loading from React.

Integrating with builds

When building with Maven, you can write an execution to create production-ready React code.

Here is a simple example to run an npm install from Maven builds with your React components added under WebContent/src –

                                                  <execution>
                                                           <id>npm install (initialize)</id>
                                                           <phase>initialize</phase>
                                                           <goals>
                                                                   <goal>exec</goal>
                                                           </goals>
                                                           <configuration>
                                                                   <executable>npm</executable>
                                                                   <workingDirectory>WebContent</workingDirectory>
                                                                   <arguments>
                                                                           <argument>install</argument>
                                                                   </arguments>
                                                           </configuration>
                                                   </execution>

This creates production-ready React code under the WebContent/build/ directory and you can trigger it calling /build/index.html.

Challenges

One major challenge was to get the Dojo and React components to talk to each other as the left navigation was still in Dojo but the main content was in React.

A quick solution was to use the publish/subscribe model to send events and communicate between Dojo and React components.

For example:

Publish an event from a React component

var e = new CustomEvent('updateSwitcher', {detail: event});
window.dispatchEvent(e);

Subscribe for the event in Dojo

window.addEventListener('updateSwitcher', function(e) {

Image shows diagram of publish and subscribe flow

Diagram/video

Step 1: Identify different reusable UI components from your application. Examples include example Buttons, Data tables, Dropdowns, Headers, Footers etc as shown in the screen shot.

Image shows identifying reusable components

Step 2: The following code creates a generalized Reusable Component, in this case, it’s the sample code for a button. You can use similar code for all the identified reusable components. (You can find the help document in references. )

import React, {Component} from 'react';
import {Button} from 'carbon-components-react';
import { Search32 } from '@carbon/icons-react';


class SearchButtonComponent extends Component {

    getData(e) {
            const requestOptions = {
                credentials: 'include',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept' : 'application/json'
                },
                body: JSON.stringify(this.props.input)

            };   
            fetch(this.props.url, requestOptions)
            .then(async res => {
                this.props.setProcessing(false);
                const data = await res.json();
                this.props.getDataFromAPI(data);

            })
            .catch((error) => {
                console.log(error);
                this.props.setError(true);
            });
    };


    render() {

        return (   
                        <div className = "searchButton">  
                        <Button hasIconOnly renderIcon={Search32} iconDescription="Search"  onClick={this.getData.bind(this)} />
                        </div>
        );
    }
}

export default SearchButtonComponent;

Step 3: Whatever reusable components created in Step2, Import those components into Parent Component and frame it according to their rendering to create the page.

import React, {Component} from 'react';
import HeaderComponent from '../common/HeaderComponent';
import SearchDropdownComponent from "../common/SearchDropdownComponent";
import DataTableComponent from "../common/DataTableComponent";
import ButtonComponent from "../common/ButtonComponent";
import FooterComponent from "../common/FooterComponent";


class ParentComponent extends Component {
    constructor(props) {
        super(props);

    render() {


        return(
                <HeaderComponent></HeaderComponent>
                <SearchDropdownComponent></SearchDropdownComponent>
                <DataTableComponent></DataTableComponent>
                <ButtonComponent></ButtonComponent>
                <FooterComponent></FooterComponent>
        );

    }
}

export default ParentComponent;

Step 4:

Image shows blocks with steps Image shows parent page

You can use the same reusable components in any pages of your product just by modifying the query parameters with respect to the specific requirements.

Example home page

The Home page was one of the first pages we created in React.

As you can see in the following image, we had a “tiled carousel view.” These Tiles are available as Carbon components in React. If we weren’t going to use React and were going to use Dojo, we would have to design the tile from scratch and keep maintaining it too. This was our motivation to use Carbon as well.

Image shows brand selection

We also used Carbon with React for our Subscriber History page. We needed a grid display, and Carbon with React came to our rescue for quick and consistent development and provided a lot more features like filter within table.

Image shows subscriber history

Performance Reports from HttpWatch plugin of Chrome: Performance improved drastically after moving to ReactJS

Image shows subscriber history data

Summary

Divide and conquer is the key here to win this integration easily and effectively without breaking existing application and moving to newer technology. Happy coding!