Using AngularJS components in React 😈

We’ve seen some informative articles on how to use React components inside an Angular app, but guides for “using Angular components inside React” were scarce. (Reasons for migrating to React at all, and to React instead of Angular 2+ are out of scope of this article and have by extensively covered by other articles and this chart of download trends for the libraries)

The GDC project was in the process of migrating from AngularJS (Angular 1) to React. For quite a while, the React-in-Angular pattern was used to perform a strangler migration one component at a time. As React ate through more and more of the project, we reached a tipping point where it could become the root app, but we were still short a few features that prevented us from reaching parity.

Being able to reuse those Angular components as-is allowed us to continue the migration without compromising existing features or our delivery timeline.

Bootstrapping Angular

This part is actually incredibly simple.

Assuming the name of the root module for your legacy Angular app is ngApp, and the name of the Angular component you want to wrap as a react component is widget

Here’s a contrived example using angular-bootstrap-datetimepicker

See the Pen Angular Bootstrap DateTimePicker in React on CodePen

This would suffice for completely self-contained components/directives, but what if there are buttons or links in the Angular component that are supposed to take the user to the now react app?

Hijacking ui-router

Assuming ui-router is being used for routing, we only have to intercept calls to $state.go

You can then choose how the app should handle those requests

Here’s an example that passes it off to react-router v4

See the Pen Angular Hijack ui-router in React on CodePen

If the old routes and new routes don’t match 1:1, you could insert a mapping function that maps old routes to new routes. An example of that can be found in our codebase here

Neutralize Angular’s location tampering

A problem we ran into was that after initializing and then navigating away from the Angular component, the browser’s address bar would become “stuck”, always resetting to the route the angular component was on.

Keep an eye on the address bar:

It turns out Angular’s digest cycle checks the browser’s location, and when it notices that the browser’s url is different from what it thinks it should be, it sets the browser’s url to the “correct” value. Since the url is now being handled outside of Angular, we need to disable this behaviour.

Looking at Angular’s source, we see it sets the url via the (🕵️private) $browser service. Here’s how to neutralize that:

Solution from Stack Overflow answer by greg.kindel

This overrides angular’s url method and change handler with a no-op

Cleanup

We’re nearly done, just need to clean up the bootstrapped angular app when the React component unmounts.

Here’s a minimal example (you can replace ngApp with the name of your angular module).

Summary

It’s always a difficult decision on whether, when, and how to migrate from a framework. For those that have started or are about to begin, I hope this article will help ease and complete that transition.

Thanks to Ben Hare, Dusan Andric, Jeffrey Burt and Francois Gerthoffert for proofreading and feedback!



Originally published at softeng.oicr.on.ca on April 17, 2017
Edited with updates June 2017

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.