I’ve been collecting resources for React Native best practices and approaches to performance. I’m also on the lookout for any more tips and guides to performance, UX, and other good practices.
My company, Vibemap, has a travel and lifestyle app for iOS and Android that is built with React Native and Mapbox. Happy to share things we’ve learned as we developed our beta and launched in the app store over the past 2 years. React Native has made it possible to deliver an app on both platforms, but it’s also presented us with a number of challenges.
One of the amazing benefits of React Native is being able to have a common code base that can be released to iOS and Android. The abstractions are not always perfect and we have found that in some scenarios who still need to write native, platform-specific modules for iOS and Android, and that means you might need to write some Swift, Objective C, or Java. As our project grew in complexity the build process also wasn’t seamless, especially the Gradle steps on Android.
It’s not just code sharing between iOS and Android that has helped us: since React Native is Javascript and React, we’ve been able to share most of our business logic and helper functions between our website and mobile app. In theory, you can even compile React Native components for the web, but that introduced some overhead in terms of webpack bundle size and complexity. Webpack is a whole other story.
We also have a design system of colors, typography, layout rules, and component styles. Using design tokens and styled-components, we’ve been able to reuse some but not all of our styles between web and mobile.
Here are the top ten lessons and best practices that have helped our team in our journey with React Native, and a few of the articles that have helped us:
And here are the top 10 recommendations:
Keeping your project in a consistent structure of screens, high-order components, and UI components helps keep you organized and productive and also makes it easier to employ code splitting, lazy, loading, and other performance techniques. The React memo and useMemo APIs are two distinct tools that help to prevent re-rendering.
Hermes has given our app dramatic performance improvements on both iOS and Android.
“Hermes helps reduce the download size of the APK, the memory footprint and consumption, and the time needed for the app to become interactive (TTI - Time to Interact).” – Codemagic
Getting the packaging of Javascript into bytecode on Android was a little mystifying, but we finally got it all working.
There are many good out-of-the-box components in React Native. That said, we’ve found that there are some excellent UI libraries that provide a UX that rivals the native experience. We’ve tried to keep the experience consistent with iOS and Android guidelines. The React Native Paper library provides us with a nice selection of basic components and also Material Design components.
Related to the UI library suggestion above, using a design system of reusable components has allowed us to keep the app experience consistent, and invest our effort into making cards, list, buttons, and other elements fast and responsive.
Optimize the list and make sure they have a key attribute, which reduces re-renders if the components data doesn’t change. For long list, use <FlatList>
instead of <ScrollView>
:
“it’s advisable to choose FlatList over ScrollView to render all countable items with attributes of lazy loading that helps in improving the app’s performance.“ - Omji Mehrota
Any console.log statements will add overhead to the Javascript thread. We also discovered from a friendly user’s security audit that by default React Native was storing some of our environment and config variables into an insecure place in the app bundle.
Another tool that’s been super helpful to our efforts is Firebase and their crashalytics tool. iOS and Android will also report crashes for React Native, but it can be difficult to diagnose the root cause. We found the stack traces in Firebase to be more informative. Plus you can report on all other app analytics and filters to specific devices that are exhibiting issues.
One area where our team is still working diligently is to speed up APIs and other data served to the mobile client. Our app loads data from a few different APIs, and we found that loading data for lists and maps was a major bottleneck. Similarly, images should be compressed and served in next-gen formats like Wepb.
“Using the RAM format on iOS will create a single indexed file that React Native will load one module at a time.“ – Codemagic guide. Note that if you enable Hermes, this optimization is already implemented.
It probably can go without saying that you should remove any unused libraries and components. That said, as a project grows and changes, existing modules can be left in your package.json. So it’s a good practice to regularly update to newer versions and check their impact on your overall app size. We greatly reduced the size of our app by replacing moment.js with day.js and using native Javascript methods in favor of LoDash.
Thanks for reading! Please send other suggestions and I’ll keep this article up-to-date. @stevepepple on Twitter and my personal blog.
Also published here:https://lzomedia.com/blog/react-native-lessons-best-practices-after-2-years-of-development/