First Contact Between Classcraft’s App and React Native

Our initial goal was to gradually introduce React Native into an existing native application. We kept our existing structure, but some views get refactored into React Native views, and they were mounted by the UIViewController on iOS or a Fragment on Android (If you attempt a similar approach, you can refer to Integration with Existing Apps docs).

The deciding factor was if we had to do any significant UI changes or bug fixes that would be easier to convert into React Native, do it. New features will be in React Native as well since all the business logic are ready — or almost — to use in our shared code. What I mean by shared code, is that all of our utils and business logic in JavaScript that applied to any platform had been exported into a folder that is used as a NPM package.

Here is a high-level overview of what was the structure of the app was after the first phase integration — remember that at this phase our React Native views were only meant to replace a UIView or Layout.

It could be an entire view that got rewritten or even small components like the badge we’re using in the messaging section.

Here is the native view we’re still using for the messages.

Noticed those green notification badges?

Those are, in fact, a React Native view that’s shown on each row by the native controller. This component is meant to receive some props from the native controller and then gather the information and display a badge, if necessary.

Then with this implementation, we can integrate this component into our both platform.

We were happy with this solution, and it improved our bandwidth since we didn’t have to replicate all the logic on each platform. But still, we had to tweaks native to declare and display our React Native views or with full React Native views, we have to declare some UIViewController and Fragment to host it and pass the required props. In short, it was a success, but not enough, the second phase will talk about this in deep.

Unfortunately, switching from native to React Native made us lose our typing. It leads us to introduced Flow — a static type checker for JavaScript — into our codebase (web & mobile). TypeScript was also an option, but with our existing web codebase using Meteor, React, Webpack and Babel, we stick to an incremental introduction of Flow across our apps, with, of course, shared types.

The Second Phase

After successfully introducing React Native into existing apps, our goal was to switch from a native container to a React Native container, which use react-navigation to display React Native and native views seamlessly. With this structure, we’ll be able to ship feature faster as we won’t have to touch any native code and it could be done by any web wizards.

So we made the switch following the docs about Native UI Components (iOS / Android). But we end up coding our own solution to host UIViewController or Fragment instead of UIView or Layout. With this solution, we leverage our legacy views into a new app structure without having to refactor it (well actually we had to handle the navigation bar with react-navigation), but that was not a tricky part. I may write a technical blog post about this strategy to display directly a UIViewController or Fragment, just ping me if you’re interested.

We still have our native application “container”, but it’s only used to launch the React Native app and to handle the sign in/up process. Even the deep linking — except for login from third parties — is a passthrough handled by react-navigation.