React Native: Two Important Lessons I Learned The Hard Way
Notice and prevent things from going in the wrong direction when building a cross-platform app.
The first months of development are like running the first hundred meters of a marathon. Builds are light, the codebase is small, no production issues or tech debt: life is good. Once we start onboarding new users, our day-to-day routine changes.
Having a React Native app in production is like sailing in an open sea. There are many important decisions to analyze and make. There is no standard solution for anything, and that’s probably the hardest thing about it. You’ll have to be smart and choose options that suit your needs best. Initial decisions you have to make:
- Expo or RN CLI
- Redux, Apollo, MobX, or Context API
- StyleSheet or StyledComponents
Even though you’re left on your own to decide what’s best for you, React Native still holds the first position when it comes to cross-platform development.
No matter how well you prepare and think you make the right decisions, things will go wrong. Most mobile apps live out of their app store rating, and a single crash in production can be expensive. However, keeping an eye on important factors will lower disaster risks (crashes or performance issues).
Two common issues with React Native are either slow transitions between screens or outdated data, and both are associated with navigation. Various things can go wrong with react-navigation, but one of the most important is how we pass data between screens.
Red Flag: Passing a lot of data when navigating makes screens dependent on that data.
Each component should be treated as an isolated view, and we should think about how to navigate to that view with as little as possible information.
You can also think of the route object like a URL. If the Profile screen had a URL, what should be in there? It’s important to understand that not all data should be in params. Params are like an option for a screen, and they should only contain information to configure what is being displayed.
Data such as user objects should be in your global store instead of the navigation state. Otherwise, you have the same data duplicated in multiple places. This can lead to bugs, such as the profile screen showing outdated data.
Red Flag: Nesting navigators
It’s recommended to reduce nesting navigators to a minimum. Always try to achieve the behavior you want with as little nesting as possible. Nesting has many downsides:
- Nesting the same type of navigators (drawer inside drawer, tabs inside tabs) might lead to confusing UX.
- A deeply nested view hierarchy can cause memory and performance issues with lower-end devices.
- With nesting, code can become difficult to follow when navigating to nested screens, and configuring deep links can become a nightmare.
Keep your navigators flat and pass as little as possible information when navigating between screens.
Animations are necessary to create a great user experience. To work with them, you should first understand React Native architecture. It consists of threads and processes, and it’s essential to understand the difference between them.
What is a thread?
It’s a thread of execution. You can think of it as a set of instructions to be executed by the CPU.
What is a process?
A process is a running program — for example, the browser (Chrome, Safari). You can see all of the processes running on your computer by opening a task manager.
What is single-threaded?
Single-threaded means that a process only has one thread of execution. This means only one set of instructions executes at once.
What is multi-threaded?
Multi-threaded means that a process has two or more threads, and it can execute multiple instructions simultaneously.
React Native is single-threaded
That means for each process; there is only one single thread. Because of this, if you have a process that has many purposes, you can have performance problems. Imagine having a process responsible for live streaming and showing a list of comments below the video. The live stream could block the comments and vice-versa because of React Native’s single-threaded nature.
React Native is multi-processed.
Instead of multi-threading, RN is multi-processed. Three primary processes are running in React Native. Each process has one thread attached to it, and this is where all confusion comes from.
- UI Thread — It’s responsible for rendering IOS and Android views.
- JS Thread — Responsible for handling all of the logic of your react native application.
- React Native Modules Thread — This happens when an app needs to access native components. For example, if you’re working with animations, you may use the native driver to handle your animations.
If you want to create additional processes, you can achieve that by using the npm module react-native-threads.
Red Flag: Animations running on JS thread
Most of the stuff going on occurs on the JS thread. While it works well most of the time, it might get jammed by things going on in your app, resulting in it being slow and unresponsive. That’s where
useNativeDriver might come to help. It tells the app to run animation on the UI instead of the JS thread.
Alternatively, you can use Interaction Manager, which allows long-running tasks to be scheduled after animations have been completed. This allows JS animations to run smoothly.
👋 Happy coding.