Integrating React.js into Existing jQuery Web Applications


One of the great parts of React.js is the ease of integration into existing web projects. Many full-fledged JavaScript MVC frameworks like Angular.js impose the architecture of your application code, thus making an integration into existing projects hard to impossible without rewriting entire parts of the frontend code.

In contrast React is barely more than the V in MVC. That makes it very simple to integrate into existing projects without revamping lots of code. You can easily try React for a particular feature, leaving the rest of your application code alone.

I'm working with React for a few month now in a traditional single-page-application. The application relies on server-side markup rendering and jQuery. Let me describe to you a few techniques I'm using to integrate React in a non-invasive way.

Let's assume we're working on an existing single-page-application with a static HTML5 layout consisting of some general elements like a header, footer, sidebar and a content container, holding the actual HTML of each individual page:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Existing Webapp</title>
</head>
<body>
<header></header>
<aside></aside>
<main id="content"></div>
<footer></footer>
<script src="jquery.js"></script>
<script src="react.js"></script>
<script src="app.js"></script>
</body>
</html>

For every internal application link we call an appriopriate controller on the server which renders the page. We could use a simple routing function to handle the ajax calls to the server and then replace the html of the main content container with the server-rendered markup. Before the actual html will be replaced, we trigger a custom jQuery event content-will-change, who's purpose will be revealed later in this article.

function loadContent(url) {
    $.ajax({
        url: url
    }).done(function(html)) {
        $('#content')
            .trigger({type: 'content-will-change'})
            .html(html);
    }
}

Instead of rendering the full HTML page on the server with an arbitrary template engine, we now want to utilize React.js to render the html in the browser for a particular page. The tricky part is how to integrate client-side react rendering without changing too much existing code like the routing function described above.

Normally you would implement a REST controller on the server and let the client handle all the rendering and routing between views. But since most parts of our existing application still rely on server-side rendering we would need to completely rewrite the routing function.

Instead we just retain server-side rendering for the React view, but instead of rendering the whole html on the server we just render an empty container and the json data into a minimal html skeleton, so the client can do the rest of the work. Putting all the json data directly into the skeleton view saves us from performing additional ajax calls later on when rendering the react components on the client.

In a Java webapp we could utilize ObjectMapper from the Jackson library to transform arbitrary Java objects into json strings. For example if we want to render a react component showing a list of books, we use the method writeValueAsString() to transform the list of books into valid json:

List<Book> books = ...;
ObjectMapper objectMapper = new ObjectMapper();
String jsonBooks = objectMapper.writeValueAsString(books);

The server controller now returns the html skeleton consisting of an empty books container and a script block to render the react component into this container passing the dehydrated json data as a parameter to the render function:

<div id="books"></div>

<script>
    var books = ${jsonBooks};
    renderBooks(books);
</script>

When the routing function replaces the html on the site via $('#content').html(html) this script block gets evaluated, forcing React to render the component into the books container:

class BookList extends React.Component {
    render() {
        return (
            <div className="books">
                Found {this.props.books.length} books
            </div>
        );
    }
}

function renderBooks(books) {
    ReactContentRenderer.render(<BookList books={books}/>, $('#books'));
}

The above code is written in EcmaScript 6 (aka ES2015) + JSX syntax. Although not all browsers support ES6 as of today, you can safely use ES6 in production by transpiling the code into valid ES5 with Babel.js. Babel also compiles Reacts JSX syntax which makes it the perfect tool for React development.


As you might already have noticed in the above code I don't use React.render to render the <BookList/> component. Instead I'm using a utility wrapper called ReactContentRenderer. The purpose of this module is to automatically unmount all react components rendered into the content container before loading a new page. This is critical in traditional single-page-applications to prevent memory leaks since React keeps references to all mounted components until they get unmounted from the DOM.

let nodes = [];

const ReactContentRenderer = {
    unmountAll() {
        if (nodes.length === 0) {
            return;
        }
        nodes.forEach(node => React.unmountComponentAtNode(node));
        nodes = [];
    },
    render(element, container, callback) {
        if (container instanceof jQuery) {
            container = container.get(0);
        }
        React.render(element, container, callback);
        nodes.push(container);
    }
};

$(function () {
    $('#content')
        .on('content-will-change', ReactContentRenderer.unmountAll);
});

ReactContentRenderer keeps a reference to all component nodes and listens on content-will-change events to unmount those components before the html of the content container gets replaced via $('#content').html(html).

If you don't unmount those components, React would never know that the underlying HTML does no longer exist. You can inspect all mounted components by using the React Dev Tools (browser extension) to manually assure that obsolete components are already unmounted.


I hope you've enjoyed this article. Don't hesitate to share your feedback with me on Twitter or use the comments below. You might also be interested in reading my article about how to render React components on Java servers by utilizing the Java 8 Nashorn engine. You should also check out my React Samples repository on GitHub, containing a bunch of client-side React examples.

Benjamin is Software Engineer, Full Stack Developer at Pondus, an excited runner and table foosball player. Get in touch on Twitter and GitHub.

Do you know Sequency?

Read More