What Issues Did We Face?

During our time with React Native, we faced a number of issues. Some of these can be attributed to our process, some to our use cases, and some to React Native itself.

Design & Experience Challenges

Platform Consistent UI/UX

Because we were integrated a few new screens into larger existing experiences, we wanted the new React Native code to adhere to both native platform patterns, and existing styling. This meant we couldn’t necessarily use the same UI design for both platforms.

Ensuring styling that felt native to each platform isn’t difficult in React Native, but it does require knowledge of the design paradigms used in each code base. At it’s easiest, this requires platform checks and perhaps custom widgets for each OS.

For us, this often required touching base with developers and designers from each platform to understand what was required, or a single style would be used for both which often led to experiences on the Android side that had a distinctly different look from the rest of the app.

In more complex situations, additional platform specific code was needed to customize the app experience.

Once such example was ensuring the proper behavior of a back/up icon. Because of where/how new React Native features needed to be integrated into the existing apps, ensuring the proper behavior of the back/up icon and back button press required Android specific native code & Android specific changes to the React Native codebase.

Changes in native design might necessitate changes to React Native code to handle the integration points

On at least one occasion, the navigational structure of the Android app changed which required us to update the React Native code for no other reason than to change how the native to React Native integration was handled.

Instead of being isolated into its own Activity, the React Native feature had to be moved to a fragment, placed within a screen with a BottomNavigationView and then coordinate state between itself and other native fragments.

This type of platform change required going back to the separate code base, making changes, updating integration, and ensuring that the new changes also didn’t negatively impact the iOS application.

Device Specific Issues

Whether you call it “fragmentation” or “diversity”, the fact remains that there are far more unique Android device configurations to account for.

On multiple occasions we discovered layouts that didn’t adapt well to differently sized Android phones. We found that animations running smoothly on the latest iPhone or Pixel device wouldn’t run well on lower end devices in international markets where Android is more widely used.

These certainly aren’t uniquely React Native problems; these are common development challenges on Android, but as the amount of platform specific checks and considerations added up we had to start considering how much time we were actually saving by using React Native.

Global Growth

During our time with React Native, internationalization became a much larger focus for the Android team. We had several international offices requesting localization and a decrease in apk size.

String localization in React Native can be done thought it does require additional setup. In our case, it would require changes to a separate repo. This increased the complexity of the localization task which was not ideal when asking for localization assistance from other teams. This contributed to a decrease in the frequency with which the React Native features were localized.

We were able to reduce our apk size over this time, but the inclusion of React Native was a sizable increase in size that we couldn’t do much to work around. After removing the last feature, our apk decreased by ~10MB from the command resource decrease and the size of React Native itself.

Integration Challenges

Integration with native components & navigation structure

In our experience, integrating React Native into existing app can be pretty straightforward if it’s an isolated feature, or can be a bit of a challenge if it’s needed to integrate closely with existing components and communicate with them.

We found ourselves often needing a great deal of bridging code to communicate between native and React Native components. At least once this code then required an update when we needed to change where the React Native component fit into our navigation hierarchy.

Tooling/Build Issue

Incorporating React Native required updates to our build processes for each app. We use CircleCI to build our projects which needed to be reconfigured to support the additional React Native build steps.

As previously shared, on the Android side this was not as straightforward as we would have hoped.

Once our build was updated to include the required React Native tasks, it increased the duration of our release build on CircleCI by ~20%.

After removal of the final React Native feature from our codebase we saw the following improvements:

CircleCI build time decreased from ~15min to ~12min

Release apk size decreased from 28.4MB to 18.1MB

The Android team also experienced issues at times with Android/Gradle build tooling being in conflict with React Native. Most recently we had been working around issues with Gradle 4.

The iOS team had its fair share of challenges as well.

Configuring the build was painful because we had a non-standard file structure for React Native. Because of our separate project repos, we pulled in the React Native repo under srcroot/ReactNative and a lot of the existing build tools assumed the default app structure which is /ReactNative/ios/…ios .

Additionally, we used cocoapods for dependency management which was originally the suggested way to include React Native, but was deprecated along the way. This was further exacerbated by our non-standard file structure and we had to include some annoying hacks in our Podfile to get it to read from the correct place.

Since cocoapods was no longer the canonical way to include React Native, Podfile updates were dependent on the community to update which weren’t always in sync. There were several versions where the css/Yoga dependency was updated but the Podfile was referencing an incorrect version.. Up until the end, we had some nasty post-install hacks to essentially sed/regex some of the include calls.

Lastly, CI for the iOS project was a pain point as well. We now had to add an npm dependency layer and make sure those were being updated properly before continuing the install. This added nontrivial amounts of time to our build step.

There was also an issue that caused a crash because one version of npm had a `package.lock` and the other didn’t which caused us to install incorrect versions of a dependency across a React Native upgrade.