Building an App with Facebook’s React Native
April 25, 2016
Although it leverages core web technology, React Native does not use webviews for UI; instead, it uses real native views. React Native isn’t limited to building views: many native APIs can be leveraged by React Native, such as networking, camera access, and push notifications. Despite React Native still being in beta, Facebook has used it in Facebook Groups, Facebook Ads Manager, and their recently open sourced F8 app.
When you might want to consider working with React Native:
- Your app needs to support iOS and Android. The majority, if not all, of your React Native code can be shared between iOS and Android. This means you can build your app faster. Having a centralized codebase will make your app easier to maintain.
- You might need to add support to either iOS or Android in the future.
- You already have a natively built iOS and Android app, but you’d like to quickly add new functionality to both platforms. It is possible to embed React Native views into existing native apps.
- Your app has a simple UI. It is surprisingly easy to whip up basic UI views such as list and detail views to React Native.
Things to be wary of:
- Complex views. If you’re relying heavily on native functionality that’s not supported by React Native, then you’ll find yourself bridging (i.e. porting native UI components to React Native) frequently. For example, if your app needs to support rendering complex graphs or sophisticated animations, you’ll probably need to implement that logic natively on iOS and Android and make it available to React Native. React Native has handled bridging over native logic and views well, but there is a learning curve and it obviously requires more effort.
- Dependencies on native libraries. Bridging also supports exposing native APIs to React Native. A lot of APIs are supported by React Native out of the box. If the APIs you need are not supported you’ll need to add support yourself via bridging. As we mentioned earlier, bridging native code takes more effort than writing it directly to React Native.
- Source control woes. Your codebase will contain 3 components: your React Native code, your iOS code, and your Android code. The more complex a codebase, the higher the chance that files will get out of sync or dependencies will be missed between your engineers. This can cause great consternation as your engineers scramble to figure out why your app is building on one of their machines but not another.
- Frequent React Native updates. React Native is still in the early stages of development, so expect the library to change frequently and account for the effort required to keep your React Native codebase up to date.
What we built with React Native
As a rapidly growing product development company, Connected has a lot of moving parts: we need to manage clients, contracts, projects, and employees. Instead of inputting this information into a bloated and unwieldy spreadsheet, we decided to take a more elegant approach by building an internal web application; we call it Allocations. The main features of Allocations are as follows: list current projects, display the contract status of each project, indicate who is managing each project, and indicate which engineers are working on each project.
We used React Native to build a native iOS and Android app for Allocations, and we would like to pass on what we’ve learned to you!
React Native Development Flow
- Run the iOS simulator or Android emulator.
What we liked
In contrast, native development on both iOS and Android have been notorious for slower compilation time compared to other forms of development, especially with more complex projects. In order to add new UI elements or pixel pushing in general, we would have to wait for the entire project to compile and run every time we want to see our changes reflected on an actual device.
Another unique tool React Native developers should take advantage of is the Inspector Tool. This tool allows developers to click on view components to highlight and inspect its current style properties (eg. margin, padding, size, color). Adjusting each UI component in our Allocations app to match the mocks was pretty simple with this tool as it provides a complete analysis of each component’s properties as well as the entire view’s hierarchy. For example, we can immediately tell whether our “TouchableHighlight” has a 15dp margin or “ProjectListCell” has a 15dp padding with the Inspector Tool as you can see in the screenshot above. With this information we’re able to easily analyze and debug each view with knowledge of its exact properties.
How to use React Native effectively
Share modules to reduce fragmentation
Through our experiences with native modules, we learned to keep the style consistent as much as possible to avoid fragmentation throughout the app. One good example was when we decided to use both Navigator and NavigatorIOS for navigation in a single app. At first, it seemed like a viable choice because NavigatorIOS provides the native toolbar and provides native iOS navigation animations as it leverages the UINavigationController class. However as the app became more and more complex, we found that we’d been generating an unnecessary amount of duplicate code while handling navigation for both platforms. In the end, we decided to go with just pure Navigator because it gives us more flexibility on exactly how we handle navigation including how we pass properties and define the animations between pages. This way we’d only have to write the navigation code once for both platforms.
Otherwise, you’ll have to manage multiple pairs of native components in different ways with mostly similar functionality. You would likely be making platform checks via if-statements all over your codebase, which we all know is a pain to maintain.
Avoid poor performance with lists
There are some performance pitfalls with React Native. One notable one we found for iOS is that the ListView component is not built with UICollectionView. Instead of leveraging UICollectionView’s ability to reuse view cells as the user scrolls down the list, React Native renders each cell individually without deallocating cells that have been scrolled passed. This means that you may get framerate drops if your cells are complex and you’re scrolling quickly (since they are continuously being re-rendered) and your memory usage will steadily increase as you scroll. React Native’s ListView has some properties you can tweak to circumvent the framerate issue, such as pageSize and scrollRenderAheadDistance. Something else to try is turning off development mode when you run the app. We had some performance issues on the main project list of Allocations which disappeared when we deactivated React Native’s development mode.
Check for updates often
Since React Native is still a relatively new platform and still in its beta stage, you should keep up to date with their changes. Facebook is not only rapidly adding new features, but also makes a lot of changes to current features. For example, importing static images prior to version 0.14 would require images to be stored in their respective project’s resource folders. In order to import the images, you would have to do a require without identifying the location of the images (eg. require(image!appIcon)). However, Facebook decided to change image management to prevent having to manage two image sets and allow the developer to decide where the images are held instead by specifying the relative paths (eg. require(./images/appIcon)). As a result, all of our image imports were no longer valid after the upgrade to 0.14, so it was a good lesson to thoroughly read through their changelogs before deciding to perform the update.
If you don’t keep up to date with the current React Native version, you could easily be writing broken or deprecated code throughout your app which would become gradually more difficult to refactor. Facebook usually provides warnings regarding potential changes to their APIs at least one release ahead of time to give developers the time to refactor their code. There are plenty of improvements and new feature sets in each release as well. Make sure you prioritize your work so that you’re not reinventing the wheel for features that will eventually be available in a near-future release.
The Future of React Native Development
React Native is already mature enough for production: just look at Facebook’s React Native showcase or our Allocations app for proof. What’s exciting is that Facebook seems serious about fully developing React Native into a robust alternative for mobile development. Since React Native is open source, we can expect significant community contributions as well. Here are a few recent developments in the React Native scene:
Thu Jun 23
Plugging In: How Going Remote-First Is Challenging Our Engineers to Collaborate More Deliberately
Going remote-first isn’t just giving our engineers the freedom to do their best work. It’s challenging them to define what and how they’ll achieve it, forcing them to work together more deliberately - in pairs and across projects. And that’s an excellent thing.
Fri Jun 17
Connector Spotlight: Ryan Lim
What does Ryan Lim, Director of Engineering, Practice, do outside of work? Most might know that he is occupied with video games, but you likely didn’t know that he’s also quite the handyman. While he’d describe himself as chill, curious, and creative, knowing that he can renovate floors, tile, drywall, electrical and plumbing, we’d also like to add capable to that list. Whether it’s letting his imagination flow while working on a project or playing with his favourite stackable blocks (can you guess what his favourite product is?), rest assured that the only vendetta from Ryan you need to worry about is in a movie. Discover more about Ryan in this week’s Connector Spotlight!