Challenges and Opportunities of Building React and React Native Apps - Discussion With Wix.com
In short
The article discusses the challenges and opportunities of building React and React Native applications. It covers topics such as integrating React Native into existing native applications, choosing the best navigation library (React Navigation vs. React Native Navigation), testing React Native apps (unit, integration, and end-to-end testing), and splitting an app into dynamic chunks using Haul. It also provides advice on staying up to date with React Native releases. The article aims to offer insights and guidance for businesses and developers using React and React Native for mobile app development.
Introduction
Last Thursday, together with Mike Chudziak (@michalchudziak), we joined Wix.com to chat about various challenges and opportunities when it comes to building React and React Native applications in today’s world.
During an hour-long video session, we covered a variety of different topics, from best practices to unobvious applications of React Native. We decided to share them in a blog post, in case they are relevant to your business as well.
Note: When possible, we have linked to resources on our website (such as blog posts or podcasts) where we have discussed a given topic in detail. In other cases, we are working on documenting them. In case of any questions, don’t hesitate to reach out.
So, what have we discussed?
Integrating React Native into native applications
React Native benefits are not only for those that are starting from scratch. If you have multiple applications on different platforms (typically on Android and iOS), you can still reduce the overall code debt by sharing selected features across the platforms.
Unfortunately, such integration is a challenge on its own as it requires your team to be experts in both React Native and native language at the same time. As a result, the Internet is full of stories of React Native being sunset due to its negative impact on the application performance or developers’ efficiency.
At Callstack, we have been doing brownfield developments for a few years already. Based on that experience, we are working on a brand new product that lets you integrate React Native into any platform in one click.
During the call, we discussed some of our ideas and compared our experience in this field to see if there is anything our teams can do better.
Callstack recommends
Pay attention to the integration between React Native and Native and how they communicate. Always run your ideas by the native developers to make sure of the performance. If possible, try to decouple both realms - while putting everything into a single folder is easiest and fastest, it increases the overall complexity. When in doubt, reach out to us. Before our library is ready to use, we’re happy to share some ideas.
Choosing the best navigation library
Navigation is the subject of discussions on almost all the panels and Q&A that I have a pleasure to be part of. The reason for that is simple - there are a lot of them. They all pursue the holy grail of navigating - native animations and user experience, combined with flexibility and expressiveness of JavaScript.
I am going to save you a long essay on the history of navigations in our community (<rte-code>NavigationExperimental<rte-code> or <rte-code>ExNavigation<rte-code> anyone?). It is a story for an entirely independent article. Instead, I’ll focus on <rte-code>React Navigation<rte-code> and <rte-code>React Native Navigation<rte-code>, both approaching this space from entirely different angles.
React Native Navigation is a wrapper around native navigation primitives. React Native application communicates with them in an imperative way, instructing the native view controllers about what to present next. The benefits are fully native animations and interoperability with different parts of your app (in case you’re working on a brownfield application). Downsides? Less flexibility and non-standard syntax.
React Navigation, on the other hand, is composed of many different parts, some implemented in pure JavaScript and some implemented natively, but wrapped in a consistent API. As a result, it is trivial to compose and build complex view hierarchies and customize your screens.
Downsides? Well, by default, animations and physics are reimplemented in JavaScript. While they’re really accurate and smooth, they’re re-implementations of OS animations in JavaScript and maybe off sometimes.
Note: It is currently possible to have the best of both worlds, flexibility, and performance, by using Native Stack with React Navigation. It builds upon native primitives, giving you a fully native experience with a nice JavaScript API - documentation.
Callstack recommends
For all the new projects, you should be good to go with React Navigation in most of the cases. It is a feature-rich and flexible navigation solution that lets you build applications with both native and JavaScript-driven animations. It is also about to ship with first-class web support, making it much easier to share code between React and React Native.
In addition to the features, documentation, and community matter a lot when choosing a library. React Navigation is a well-maintained Open Source library that receives a lot of contributions from the developers that use it every day.
One of them is Satyajit Sahoo (@satya164), who is a core contributor to it at the same time. With such expertise on board, we’re prepared to solve any challenges that may happen down the road!
Ways to test React Native apps?
Testing is an important part of making sure that what we release to production works the way we programmed it to be. There are many established ways one can test their JavaScript apps. Although JS is usually run in a browser environment, with React Native there’s nothing preventing us from making it power our mobile apps. And thankfully we can reuse the way we test our browser apps to some extent.
Various testing approaches can be usually broken down into the following categories: unit, integration, and end-to-end tests. Each having its own set of benefits, drawbacks, and scope of use.
The first group describes small test cases that are focused on ensuring single units (hence the name) of your application work on their own. They’re fast to run, well-scoped, and are best when testing crazy edge cases of our leaf components or business logic.
Once we have our units tested, we need to make sure that they behave well together in a system that happens to be our app. We want to test how they integrate with each other. Integration testing in React Native apps is usually about testing bigger components consisting of smaller ones. We can let React render them into the memory and then assert on the output.
Unit and integration tests are only testing JavaScript code in a fake Node.js environment. However, the beauty of React is that it doesn’t care about where it’s rendered. Using custom renderers, we can render React to DOM, iOS, Android, or into the memory of a Node.js environment. Just like our tests do. And because the majority of our React Native apps code is written in JavaScript, it covers most of our testing use cases.
We’d lie if we say that’s it when it comes to testing. Even with a full unit and integration test coverage of our JS and React code we can still hit bugs. The ones that come from an integration with a real environment or from a lacking quality of our mocks. For example, mobile devices can have different operating systems, and each of them, a different version. They may have different permissions or networking setup, rendering our app unusable even though our JS is perfectly fine.
That’s why we need end-to-end tests. They make your app run on real devices and assert on that, similar to how your users would use it. With a small suite of E2E tests, as we call them in short, we’re able to eliminate most of the uncertainty on the edge of React and the platform it renders to. Beware that these tests are slow, expensive to run, and tend to fail for reasons unrelated to your code changes. In a healthy codebase should be a cherry on top of your testing suite.
Callstack recommends
For unit and integration tests of React Native components, our preferred choice is our own React Native Testing Library. It is a collection of utilities that help you write clean and high-quality tests that are resilient to code refactors. They also prevent you from common pitfalls by restricting what you can interact with when testing. It shares the same familiar API known from other libraries from the Testing Library family, making it easy to jump back and forth between testing different environments.
For integration tests, we recommend setting up Detox, which is an Open Source library created and maintained by Wix, bringing you the end to end testing experience at minimal latency.
It is also part of the React Native development cycle, where we use it to test the framework ahead of the release. As a result, you can be sure that Detox is always supported on the React Native version you’re currently running.
Splitting an app into chunks (and loading them dynamically)
It is possible for a React Native application to download a proprietary code that is hosted on the Internet and inject it dynamically into the application. This functionality is not supported by default inside React Native and its bundler Metro. However, it can be achieved by using Haul - our Open Source library.
Haul is an alternative to Metro and on a high-level, it allows you to bundle JavaScript code with Webpack. From the very beginning, the road map and development of Haul were focused on addressing the needs of our clients, with the focus on enterprise customers and their requirements. One of these challenges is the increased bundle size as the application grows.
At Callstack, we are developing a feature called “multi-bundling” to address that particular problem. It works by splitting the bundle into multiple smaller ones that can be loaded on-demand, as they are needed. This allows to ship only the basic functionality or and load more code as need pre-load React Native instances with dependencies in brownfield apps.
Callstack recommends
If your application is growing in size or consists of different modules that could be injected into the application realtime (anyone building an operating system?), then, Haul might be your answer.
Note: At the time of writing this article, a few PRs to React Native enabling this architecture haven’t been merged yet. It is possible to use it, but you will have to patch a few files yourself.
How to stay up to date with React Native releases?
React Native is an Open Source library that lives under the Facebook organization on Github. It is a mirror of the code that is hosted internally at Facebook as a part of their mono-repository architecture. As a result, Facebook developers run React Native straight from the source.
On top of that, React Native is published to the npm registry for those that want to consume it like any other JavaScript package. This process is done by the volunteers and tracked in real-time on Github, in its dedicated repository.
As soon as the branch is cut, the owner of a current release creates an issue corresponding to the release. It is the place where we track everything, from outstanding action items through commits that have to be cherry-picked in order to release stable. A good example of such process could be the issue focused on the upcoming release (at the time of writing this article) - 0.63.
Callstack recommends
Watch the Releases repository, especially the issues section, for all the latest updates on the upcoming releases. All the arrangements between core contributors are shared there, making it super easy to understand the direction that we’re moving for a particular release.
What’s more, you can actively participate in the release process by helping with the changelog (PRs section), testing release candidates, and suggesting potential regressions and commits to cherry-pick in order to fix them.
Summary
At Callstack, our focus is to help your business achieve its goals by empowering your React and React Native development teams. We hope that the insights given not only answer your questions, but actually inspire you to build a mobile app with React Native.