We prepared some recommendations related to the challenges and opportunities of building React and React Native apps. Check them out!
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.
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
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.
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?
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.
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.
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.
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.
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.
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.
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.
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.
If you have any questions or challenges around React or React Native, don’t hesitate to get in touch. We are eager to take a closer look at your existing architecture and help you move forward.