How to create a truly native experience for your React-Native app?
Developers can be resilient to adopt React-Native to build a mobile app and may have concerns about the performance, reliability, or that the app produced won’t feel native or lag behind.
Let’s first start with this question: What are the key ingredients for an app to actually “feel native”?
In my opinion, this feeling of nativeness is all about providing a smooth and enjoyable user experience. This experience you often lack on the web. A great mobile app is intuitive, easy to navigate, and responsive with minimal lag. It should have engaging visuals and effects. And the app should quickly display data, or provide a pleasant way to wait if necessary.
Creating a great user experience for React-Native app is a combination of building enjoyable animations, gestures and effects, providing a remarkable look and feel crafted with a one-of-a-kind design and making use of the device native features to enhance the experience and avoid latency. By focusing on these elements, we can create a React-Native app that offers a smooth user experience. Let’s dig in details on how we can achieve this in the React-Native ecosystem.
Animations, gestures and visual effects
Animations and gestures are important in any mobile application. They help to create a smooth and interactive user experience. Animations provide visual feedback to users when they interact with the app, making it more responsive and engaging. Gestures, such as touch and swipe, enable users to interact with the app in a natural and intuitive way, improving its usability and making it more user-friendly.
There are several ways to create animations and transitions in a React-Native app, and the best approach will depend on the specific requirements of the animation. One common way to create animations is to use Animated. It provides simple ways to create animations and transitions but can be limiting as we can only animate non-layout properties. PanResponder provides a way to access native touch. It makes single-touch gestures resilient and can be used to recognize basic multi-touch gestures.
On the other hand, Reanimated is another great option to consider. It allows us to create complex and interactive animations and transitions using a declarative and flexible API. It also provides support for animating gesture-based interactions, such as panning and swiping and integrates with the gesture-handling system in React-Native. Reanimated is designed to be highly performant, with support for asynchronous and low-priority animations, and is widely used in production React-Native apps.
If your animations are very complex, a great library to consider is Lottie. By exporting Adobe After Effects animations as JSON, the library can render the animation natively on our React-Native application (and also on the web if we want). The animations can be used to animate various elements on the screen, such as icons, buttons or loading effects. Lottie Files' website is also a great resource. It offers a collection of pre-made Lottie animations that can be downloaded and used in our own projects. There’s also an alternative to Lottie called Rive which promises smaller and faster animations. I haven’t had a chance to use it but you might want to check it out.
Another library I recommend to make an app very special is Skia. This library can be used to render 2D vector graphics, such as text and geometric shapes. We can combine those rendered shapes with Reanimated to create our very own morphing effects.
Design a one-of-a-kind mobile app
It may seem like a good idea to make a mobile app look like the OS, as it ensures the users get the familiarity of an interface they know and they are more accustomed to. However, it also means creating two very different user interfaces for the two platforms, missing the point of using a technology like React-Native where we can use one code for multiple platforms.
What I believe is generally better is to create a unique, intuitive, and adaptable design for our apps that stand out from the OS and other apps. It can also be beneficial to follow the design guidelines for the specific platform (the Human interface guideline for Apple, and Material design guideline for Google) to help your app to integrate seamlessly and improve the overall user experience.
For small applications or prototypes, it can be interesting to pick an existing UI library to save time and effort by using pre-built components and design patterns. However, for large apps with complex user interfaces, using a pre-built UI library can be less efficient and it is probably a better idea to build a custom set of components. Regardless, having a collection of reusable components will improve the consistency and quality of the app’s user interface and can help ensure the app is optimized for different screen sizes and device types.
There are many popular UI libraries for React-Native, and the best one will depend on specific needs and preferences. One that I personally like is RNUILib from Wix, providing sets of beautiful UI components to get started quickly with basic components like Button, Avatar and Card and more sophisticated ones like Hints, ColorPicker and Drawer. Other libraries to consider are MagnusUI or UI Kitten.
When it comes to navigation, React-Navigation is the solution backed by the React-Native team and the most commonly used navigation library. It provides a simple and flexible way to structure the navigation in an app, and allows us to easily implement common navigation patterns such as a stack of screens, a tab bar, and a drawer menu. It has all the tools needed to create a consistent and familiar navigation experience for both iOS and Android platforms, to build a clear and concise navigation experience for users of our apps.
It is important to not forget about using device-specific features. With React-Native, we have access to many device features, such as the camera, GPS, deep-links and push notifications. Using these features in the app can help improve the overall user experience and make the app feel more native. Using Haptic feedback for example can provide a more immersive and engaging experience. Datetimepicker is yet another library we can use which provides access to the native iOS and Android date and time pickers.
This list is not exhaustive and give a few possible examples. There are other great libraries available to improve the experience of an app. Doing some research and comparing the libraries can help to significantly make our app feel great. There is always the option to implement a native module and bridge it to React-Native, but this can be complex, especially if you are not familiar with native development.
React-Native contributors also provide a great guide about improving the user experience, it’s a good read to have.
Maximizing the app user experience
Optimizing the performance of a React-Native app is an important part of improving the user experience and making an app feel more native. A well-performing app is more responsive, smoother and more enjoyable to use. There are different techniques and approaches to improving an app's performance, I recommend you read this official article from the React-Native team which goes through common sources of performance problems.
In the meantime, I want to touch on some points beyond the basis of simple performance techniques that will make a difference in the user experience.
The offline experience
For me, one important part of using a native app is the possibility to use it offline. Or at least to see my previous data offline. Building an offline mode for an app improves the user experience in situations where there is no internet connection available. But, it can also be beneficial to use it to store the previous user’s session and restore the data the next time they open the app. It can reduce the need to fetch data when the user starts using the app, removing the need for spinners which can make the app look cluttered and overwhelming.
The simplest way to store data on the user’s device is to use AsyncStorage. But when using a library to manage server data such as React-Query or Redux, we can use a persister, which is an adaptor between the app state and the device’s storage, to keep the data in memory for future use. Those are usually documented in the state management library you use.
Webviews should not be used
Webviews are not as efficient as native components, and can often lead to slower app performance and a less-than-optimal user experience. They are essentially “web pages inside an app,” and might not be optimized or well-supported on all platforms and devices. When a webview is used, the web page runs in a browser, which adds an extra layer of complexity and overhead. This can result in longer load times, especially if the web page is loaded from the internet. In comparison, when you use React-Native components, they are embedded and rendered directly by the app, which enables them to perform better and provide a better user experience.
Monitor how users are interacting with the app
Monitoring our app can help identify and fix any bugs or performance issues that may be affecting the app’s functionality or user experience. This can improve the overall quality of the app, and help to prevent user frustration or dissatisfaction. It can also provide important metrics and data that can help us to understand its overall performance to make decisions about how to optimize and improve the app.
A popular error-tracking and monitoring tool is Sentry. It provides real-time notifications when errors occur, along with detailed information about the error. We can also monitor how long it takes for a user to navigate between screens. Other tools to consider are Bugsnag or Instabug.
Moreover, adding an analytics tool to our app can help us to better understand how our users are interacting with the app and identify opportunities to improve the user experience. For example, we can get valuable insights into how users are interacting with the app, and use the data to optimize it and identify areas where users are dropping off.
Testing with real users
Testing the app with real users can help to identify any areas where the user experience needs to be improved. By testing the app with real users, we can identify these issues and make changes to the app to address them. This can help to improve the overall quality of the app and provide a better user experience. Additionally, testing the app with real users can provide valuable feedback and insights that can help to improve the app in the future. Users may have ideas for new features or improvements that can enhance the app, and testing with real users can provide this valuable feedback. By conducting user testing and incorporating the feedback received, we can make sure our app provides a great user experience. Some popular options for finding testers include UserTesting and Applause.
Conclusion
Whether a React-Native app feels native to a user mostly depends on the willingness of the product teams and the developers to spend time improving the user experience, the quality of the app’s user interface and the performance of the app. While React-Native has its limitation and may not always provide the same level of customization we might have with a regular native app, in most cases, apps generated with React-Native can reach the same user experience, with many of the same design patterns and native performance.
About me
Hi, I’m Alexis! I’m a Mobile Engineer who focuses on building and supervising React-Native applications. I have expertise in solution architecture for large-scale applications, and I enjoy spending a lot of time learning and experimenting with new technologies for my future projects.
You can follow me on Twitter: @alexmngn