10 Things We Learned While Building a React Native App
There’s a lot to be excited about with React Native. With it, building iOS and Android apps becomes a fun, enjoyable experience. However, there are a few caveats — things that my partner Nicholas Alan Brown and I wish we had known before we embarked on the journey of making a production-ready app.
As our first React Native app, and all while we both had full-time jobs, we decided to make an iOS app for the Bhagavad Gita — the ancient Hindu religious text. I had experience teaching the text at an Indian university, and thought it would be a simple yet practical project. The screenshots below show some scenes from the final product, available on the App Store.
While building the app was a joy, there were definitely some roadblocks along the way. In this post, I’d like to highlight 10 difficulties that we faced, and in many cases, solved. I think this might be helpful to other independent developers who don’t have the time or resources that big development shops do.
- You MUST bundle your app before submitting to the App Store
This is somewhat of an embarrassing pitfall, but it does happen to a lot ofReact Native developers, especially if you don’t have previous XCode / Swift experience. Even though your app may run smoothly on the XCode Simulator, you still have to bundle. If you do not and submit the build to the App Store, it will get rejected every time, usually with a notice like this:
You can see that it took 2 rejections before I caught on that I was doing it wrong! Although it’s exciting getting started and you want to get your app on the App Store ASAP, I would suggest not submitting until (a) you can run your app on your device with a bundle, and (b) you can run the app on your device through TestFlight. Here is some more info on bundling your app. Also, the documentation on bundling is a little tricky, so we will cover that more later on.
2. Upgrading React Native versions
This was somewhat of a difficulty for us. Sometimes we would upgrade to the latest release, and everything would break. Then we would struggle to find stable ground again. The fail-proof method of re-installing dependencies was to delete the entire node_modules folder, shut down all processes, then npm install, cmd+shift + k to clean the build, cmd + shift+b to create the build, and then cmd + r to run the app again. Learning this was very helpful when the latest build didn’t work and we needed to step down a version.
3. Scene Transition Animations
In a reddit thread with the React Native team, we asked the team why the scene transitions with the Navigator component are so slow. It is true that if you simply use the Navigator component, you will find really choppy animation while transitioning between scenes. This choppiness becomes much worse in Android, though I haven’t tried this with the latest versions yet. The React Native team responded by saying that they are working on offloading the JS animations to native code, since the JS code piles up and causes frame drops. There is also the InteractionManager module, documented here. We found that Navigator together with theInteractionManager works quite nicely. However, by this time we had already invested heavily in NavigatorIOS, which is faster and has better transitions, since it is native code. The downside to NavigatorIOS is that it is difficult to manage state with it in complex apps. Fortunately, our app was fairly simple without a large number of routes. In the future, we will be looking to useNavigator instead.
4. ANALYTICS!!!
This was the most frustrating of all the issues we had, simply because we spent so much time trying to figure out a solution. When we first started, we knew that analytics would be a huge part of driving our marketing and development strategies post-launch. We tried to go for a Google Analytics solution, but couldn’t find any React Native packages that actually worked (see the SO post here).
Finally, I decided to write my own bridge for Segment Analytics. I was inspired to do this after hearing Chris Smothers (creator of Posyt) describing how he did the same. Basically, the steps are (1) add the Segment pod to a podfile — instructions given here under the heading Bundling Integrations. The React Native docs also describe how to use podfiles here. (2) In the same section, where it says SEGAnalyticsConfiguration, you add the configuration statement to your AppDelegate.m file. (3) You write a helper module that exports theSegment analytic functions to your app — see the gist here. Finally, you can call the AnalyticsHelper module functions in your app when a user logs in, opens a page, etc.
5. Animations
Animations are a nice feature for lots of apps. Whether it’s when a user submits a comment (notice on the iPhone how the message slides up), or a fade-in on entering a screen, or swiping animation, this is definitely important.
While the React Native Animated module is great and pretty well-documented, there are some things that can make the process easier. We started using theAnimated module for everything until I discovered Animatable. If you’ve ever used the CSS library animated.css, this is very similar — it has a ton of easy-to-use animations right out of the box, and is easily configurable. We utilized animations in particular for our onboarding sequence, which produces a carousel on top of the home screen, which expands and loses opacity upon entering the home screen.
6. @notbrent
This guy is simply amazing. Every time Nick and I had a problem — whether it was with scene transitions, onboarding carousel, swiping animation — the answer would undoubtedly come from Brent Vatne. This guy has been a tremendous contributor to React Native and has a ton of great examples to follow. Follow him on Github. Brent, thanks for all the help :).
7. CodePush
Use it. Just do it. Trust me, it is worth it. I got turned on to CodePush from a presentation at our React Native NYC meetup. Jesse Sessler and Bruno Barbieri from Delivery.com spoke about how they integrated React Native in Delivery.com’s existing iOS app — check out their Medium post here. They also shared how using CodePush has been revolutionary for their company. CodePush allows you to push updates to your apps without going through the traditional App Store updating process. This means your users get your updates silently without any prompts, etc. This is great for many reasons. For one, you can keep reviews for your app instead of losing them for each subsequent release. Also, it allows you to push bug fixes really fast. Thedocumentation is very easy to follow, too.
8. Social Sharing
This is something we struggled with. When we released the app on TestFlight, one of the common remarks was that it took a really long time for the social sharing options to appear after hitting the share button. We were using thereact-native-activity-view package, and decided to scrap it. Now we are using the react-native-social-share package. Instead of having options for everything from email, to text, to Twitter, etc., it just has Facebook share. We found this was significantly faster, but still not great. It turns out that social sharing actions are generally slow, even in native Swift apps, but it would be nice to see some improvements in this.
9. App Icon, Launch Screen, etc.
These are things that can be frustrating if you don’t have previous iOS experience. I was lucky that Nick is a full-time product manager for mobile apps, so I let him cover this stuff, but it is still pretty confusing. And once you get the app icon and launch screens working properly, you still have to submit all different kinds of screen shots for the App Store submission. I’m not an expert in this, but I did find this website helpful for getting the different app icon sizes. I also found the tutorials from Ray Wendlich to be helpful, though the process for submitting to the App Store has changed since the post somewhat. All I can say is just bear through it :).
10. react-native bundle command
First of all, the documentation that comes in your AppDelegate.m is not up-to-date (easy PR for someone). The react-native bundle command has changed in the newer releases, and now has many different options. Here are some of them; (1) — platform this is either ios or android. (2) — bundle-output this is the location of your main.jsbundle file. For us it was ios/main.jsbundle. (3) — dev usually you want to set this to false. (4) — entry-file this is the location of your index.ios.js file (if iOS). if it is located within your directory’s root, it would just be index.ios.js. (5) Finally, — assets-dest — this is very confusing, since it would seem that this is where you specify to bundle your assets. However, in most cases, you don’t want to specify this. Instead, there is a file within your node_modules/react-native/packager directory that bundles your assets for you. Why this isn’t documented very well, I’m not sure. Maybe now it is, but when we were trying to bundle, it was very hard to find this information. Anyways, just run the file node_modules/react-native/packager/react-native-xcode.sh and it will bundle your assets for you. Voila!
Conclusion
I hope you enjoyed this post. Despite all these roadblocks, I am confident thatReact Native has a huge future in mobile development. The two of us were able to get an app up to production-readiness and deployed in about 2 months. Please take the time to check out the free or paid version of the app and give us your feedback. Our website for the app is here.
Also Nick and I would love to hear from you. We help organize the React Native NYC meetup and love building apps on the web and for mobile. Happy coding!