Notice:
This post is older than 5 years – the content might be outdated.
Last year I received the assignment to create a sophisticated Android and iOS application for a European retail chain, so their employees could be more productive in their daily routines. The goal was to create a React Native app to enable their employees to scan and maintain the retail chain’s inventory in an easy and convenient way. I began working on the project in October 2017 and finished my work in December 2018. While creating the inventory app I had the opportunity to learn and gained a lot of insights about the pros and cons of using React Native.
In this article you will find a brief summary of the lessons I learned while working with React Native on a daily basis for over a year. Please keep in mind that some of the lessons I learned refer to our technology stack which I attached below. For clarity reasons I divided this blog entry in four sections: ‘The Good’, ‘The Bad’, ‘The Ugly’, and ‘Additional Learnings’.
The Good
It’s React
As a front-end engineer with a native iOS development background, I found it very easy to get started with React Native since I already had used React and thus the concept of a component based architecture was familiar to me. React Native itself is just like React with the distinction that it uses native components instead of web components as its building blocks. Due to the popularity of component based architectures in modern frameworks such as React, Vue, and Angular I would argue that the learning curve for most front-end engineers who already used a component based framework is low.
Fast Feedback
Compared to native iOS app development, React Native offers a feature that is called Hot Reloading which is well-known to front-end engineers and Android developers. The idea behind Hot Reloading is to inject edited files to an already running app without the need to recompile (on the web re-bundle) the application, and thus the developer doesn’t lose the running app state [3].
Hot Reloading is especially useful when tweaking user interface components, since it makes time-consuming re-compilation obsolete. Nevertheless, Hot Reloading will only work to a certain degree, since it does not work when updating application logic and other parts like environment variables. Overall, I really miss this functionality when developing iOS apps in my spare time.
A great demonstration how Hot Reloading works in detail when developing a React Native application can be seen in the following video:
Testing
My team and I decided to use the Jest Framework which was also created by Facebook, to test our React Native app. Jest worked really well for us, as it was very easy to integrate into our React Native environment and it was pretty straightforward to use. We also loved the detailed documentation of Jest. Ultimately Jest allowed us to write unit and integration tests without any constraints. A big benefit of having a single code base compared to writing two native apps (iOS + Android), is that the cost to write tests declines and thus becomes more efficient.
The Bad
Navigation
We had some trouble implementing a well working navigation concept. React Native itself only provides a native wrapper for the iOS navigation, NavigatorIOS . For Android there is no out of the box solution provided by React Native. The official documentation recommends using a library named React Navigation for a cross-platform solution in JavaScript [4].
We followed the docs‘ advice and added React Navigation as a dependency to our project in order to implement our navigation. However, we weren’t really happy with our decision as we often found bugs and faced difficulties using the library in combination with Redux to manage our navigation state. Later we also had to learn that the official Redux integration will no longer be officially supported with the next major React Navigation version (4.x.x) which was a real bummer [5].
Next time I would try the open source library React Native Navigation (this name is easy to mistake for React Navigation) made by the company Wix.com . On first sight this library seems to be a good alternative as it also offers Redux support [6] and even provides a full native platform navigation on Android and iOS. [7] The main reasons we didn’t swap React Navigation for React Native Navigation was that our app was already too big for such a change, and it would have been too much effort.
Missing Style Properties
While using React Native I often missed the fact that not all CSS properties were available in the React Native StyleSheet abstraction, which is pretty similar to the CSS style sheets on the web platform [8]. Don’t get me wrong here, I love the fact that I can style my React Native components using known CSS properties, but sometimes it was a bit annoying to find out that some properties are just not available on the React Native StyleSheet abstraction like background-repeat, filter, and box-shadow for example.
On the upside, we could always style our component as needed but it often required some rethinking. You can find a full list of all React Native StyleSheet properties here.
The Ugly
Upgrading React Native
Often we had several problems when we tried to update our React Native version with its dependencies to the latest version by using the react-native-git-upgrade module that is provided by the React Native team.
Interestingly there were versions out there where the module worked but more often it did not for us. As a result we had to update our dependencies manually which was a time consuming but very important task as React Native continues to get better and better with every release.
I generally felt that upgrading React Native with its dependencies was more time consuming compared to updating dependencies in either a native or a web application. Personally I think that the process of upgrading React Native versions in the future will become easier as the platform slowly but steadily evolves and gets more mature.
Platform Specific Updates
One of the things I missed the most when benchmarked to pure native app development, was that platform specific updates took a while until they were available on React Native.
In our case we had to wait several months until React Native shipped the SafeAreaView component. The SafeAreaView was needed in order to render our components within the safe boundaries of an iOS device which affects newer iPhones (X, XR, XS, and XS Max), since those devices limit the screen as they have rounded corners and camera notches.
Sure, we could have manually created a React Native component in order to guarantee that our content stays within the devices safe boundaries, but it is always easier and more convenient to use officially supported components rather than creating your own.
Another characteristic that annoyed me was that I had to use some workarounds in order to execute our React Native app after I updated my system to the newest macOS (Mojave) and Xcode (10) version. Initially our app didn’t run on Xcode 10 because changes to the Xcode build system have been made [9]. Please note that I don’t blame React Native here, but for me as a developer it means that I have to be very cautious before updating to the latest macOS and Xcode versions from the first day they are released. This is the case less frequently when developing a native or web application.
Missing Native Modules
Sometimes my team and I missed some modules which React Native oddly didn’t ship. As a result we had to add extra dependencies like React Navigation, React-Native-i18n , and React-Native-Config (Configuration Variables) that aren’t needed when developing a native iOS/Android app, since they are already included in Apple’s and Google’s mobile SDK.
While this isn’t necessarily a bad thing, it definitely requires some effort to find good and reliable libraries or the time to implement your own solution. Also, please consider that all added dependencies have to be updated from time to time.
Additional Learnings
Documentation
In my first 6 months using React Native I noticed that some parts of the official React Native documentation were lacking some information. I particularly struggled with the Animated and LayoutAnimation API, because some parts of the docs were just incomplete [10]. I often had to look in the React Native implementation itself or read some articles online to understand how to animate a simple React Native component.
Having said that, I noticed that the overall documentation is becoming better and better every month. The Animated and LayoutAnimation API part in the docs is looking more complete now. At this point, I would like to give a shout out to the React Native Team!
TypeScript Support
In the beginning there was a short period of time where we thought about writing the inventory app in TypeScript. TypeScript can be particularly interesting for team members with a native mobile background, since Swift and Java (used for iOS and Android) are both static typed languages, where JavaScript is not. Using a typed language like TypeScript – a typed superset of JavaScript – facilitates spotting bugs while typing the code and also enables a more powerful auto completion.
However, TypeScript support at the time (October 2017) wasn’t good enough and so we went on with JavaScript. On the upside, the TypeScript support nowadays seems to be great and I would definitely give it a try and use it with React Native [11].
Warnings
What I immediately noticed after setting up React Native with the CLI (command-line interface) for the first time is that out of the box my newly generated project had several warnings. I got annoyed by the constant stream of warnings that occurred every time I compiled and executed the inventory app.
For me this behavior was a bit disturbing, since I learned in my early career that warnings should be avoided. Although this fact isn’t crucial when developing React Native, it still bothered me that our newly created project had so many warnings. I still tried to get rid of all warnings but wasn’t successful and learned to live with it.
In defense of React Native, you will likely also face the same situation when you add dependencies to an iOS, Android, or Web project.
Redux
In order to manage our application state we decided to go with Redux, mainly because some team members had already used it in another project and loved it. After using Redux for over a year within our app, I must say that it worked well but I noticed that some team members (myself included) had some problems learning Redux, because it required learning new concepts and thus often a new way of thinking. I would argue that Redux has a pretty steep learning curve and can be a bit intimidating at the beginning.
Overall, Redux worked for us, but required a lot of effort to get used to. Ultimately, Redux was probably not necessarily needed, as our application state was rather small. Today, if I had the chance to choose a solution to manage our app state, I would first go with the React Context API and use it until the app state becomes unmanageable, if ever. At this point I highly recommend you to read Dan’s article ‘You Might Not Need Redux’ first, before deciding whether to use Redux or not [12].
GraphQL & Apollo
GraphQL is a query language for APIs with a runtime in order to fulfill those queries. In summary, the idea of GraphQL is to give clients more flexibility as they can ask exactly for the data they need. [13]
We used the Apollo framework (implementation of GraphQL) to create a GraphQL backend for our React Native application – often called BFF (Backend for frontend) –, so we could be more flexible on the client site and also pre-process some data on the BFF first. The whole idea was to decouple backend logic from the frontend.
After using Apollo with GraphQL for over a year, I must say that our setup worked well, as it was stable and resulted in a cleaner code on the client side (React Native) than it would be the case without. Ultimately, one must not forget that it is much easier to just use existing REST-APIs (if applicable) without creating a BFF, since writing and maintaining the BFF also requires time and effort.
Before creating a BFF, please make sure that it makes sense for your project constellation. If your project is rather big, or requires data from multiple data sources, GraphQL might be the right idea though.
Conclusion
Would I use React Native in the same project again?
Well, after analyzing and learning about all project requirements (weren’t all known in the beginning), our project could also be created by solely relying on modern web technologies. This is mainly due to the fact that the application primarily only displays data, doesn’t use much animation, will only be used internally (no app store requirement), and the dedicated mobile scanner itself registers as a simple keyboard. With the help of modern web standards like the Service Worker and the Web App Manifest, an installable and offline capable web application could have been created.
Sure, React Native wasn’t a bad choice either as it worked for our use-case and the finished app received much praise. However, developing a web application would have been faster since many problems which I already described above wouldn’t have existed, and other things like app deployment would have been simpler and thus would allow us to move at a faster pace.
As a result, I think that React Native has its right to exist as it already allowed our team and larger companies such as Uber, Walmart, and Tesla to successfully create sophisticated applications [14]. Before deciding whether to use React Native/native/web technologies, you should first start thinking what the project requirements really are and then balance pros and cons of each technology against each other, and ultimately decide with all team members what technology to use.
Read on
Need more support working with React Native or other mobile technologies? Have a look at our portfolio for iOS and Android. If you want to get your hands dirty, you might want to join us yourself.
Literature
[1] https://facebook.github.io/react-native/docs/tutorial
[2] https://webpack.js.org/concepts/hot-module-replacement
[3] https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading
[4] https://facebook.github.io/react-native/docs/navigatorios
[5] https://reactnavigation.org/docs/en/redux-integration.html
[6] https://wix.github.io/react-native-navigation/#/docs/third-party?id=redux
[7] https://wix.github.io/react-native-navigation
[8] https://facebook.github.io/react-native/docs/style
[9] https://github.com/facebook/react-native/issues/19573
[10] https://facebook.github.io/react-native/docs/animations
[11] https://facebook.github.io/react-native/blog/2018/05/07/using-typescript-with-react-native
[12] https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367
[13] https://graphql.org
[14] https://facebook.github.io/react-native/showcase
You can still use Redux alongside React Navigation, the library is just dropping explicit support for storing the internal navigation state in Redux, something that no other navigation library supports as far as I know and that just complicates things for the users in my experience.
Hi @brentvatne,
Thank you for the comment!
Yes, you are right. We still could use Redux with React Navigation (version 4.x.x), but it doesn’t feel great that the official support for storing the internal navigation state is dropped.
However, I quite understand their decision but at that time we felt left out and thus were a bit frustrated 😉
You mention in the article that react native navigation provides redux support, but to be clear that is only to the same extent that react navigation supports it – you can use redux just fine but you can’t store the internal navigation state in your own reducer.
Thank you for this hint: „However, developing a web application would have been faster since ..“