Saturday, November 28, 2015

React Native Tip: TouchableOpacity supports multiple children

React Native's TouchableOpacity used to require a single child element. To attach a touch event handler to multiple components, you had to first wrap them inside a container <View>:
// Old way
    <Image ... />
It wasn't documented anywhere, but one bonus effect of commit 725053a is that TouchableOpacity now has an Animated.View root which supports multiple children. So if you've upgraded to React Native 0.14.0 or higher, you can now get rid of the container view when using TouchableOpacity:
// New way
  <Image ... />
TouchableHighlight and TouchableWithoutFeedback still require a single child as of RN 0.16.0, though I would normally avoid using them anyway — TouchableHighlight often creates undesirable artifacts, and TouchableWithoutFeedback leads to a poor user experience when used alone.

Monday, October 19, 2015

Playing sound in React Native apps

I've open-sourced 'react-native-sound', a native module for playing sound files in React Native apps. It supports preloading and sound mixing with an audio player pool. The module is currently iOS-only, but an Android port is coming soon.


npm install react-native-sound --save

In XCode, right click Libraries. Click Add Files to "[Your project]". Navigate to node_modules/react-native-sound. Add the file RNSound.xcodeproj. In the project navigator, select your project. Click the build target. Click Build Phases. Expand Link Binary With Libraries. Click the plus button and add libRNSound.a under Workspace.

Usage example

Now you're ready to play sound clips in your React Native app. Just drop sound files in your XCode project and call the following APIs from JavaScript.

var Sound = require('react-native-sound');
Sound.enable(true); // Enable sound
Sound.prepare('tap.aac'); // Preload the sound file 'tap.aac''tap.aac'); // Play the sound 'tap.aac'


  • Sound.enable(true) must be called before playing any sound.
  • Sound.prepare(...) preloads a sound file and prepares it for playback. If you do not call Sound.prepare(...) beforehand, will still work, but there might be a noticeable delay on the first call.
  • You can make multiple calls at the same time. Under the hood, this module uses AVAudioSessionCategoryAmbient to mix sounds.
  • The module wraps AVAudioPlayer which supports aac, aiff, mp3, wav etc. The full list of supported formats can be found at

Tuesday, September 15, 2015

What I learned from building a React Native app

React Native is Facebook's open-source framework for building native mobile apps using JavaScript. Unlike PhoneGap/Cordova, React Native provides bindings for native UI controls which totally outclass HTML-based hybrid solutions. After playing with the sample app for a while, I decided to jettison my Cordova codebase and rewrite the Circadi app using this new framework. It took me about 96 working hours to finish an MVP, now published on the App Store. My overall experience with React Native is positive. I'm going to give an account of my key findings below for people who're considering to adopt the framework.


Developer productivity

React Native enables developers to write native apps in JavaScript with ECMAScript 5/6 features and optional type checking using Flow. This alone is a huge boon to my productivity even if cross-platform code reuse were never promised. Having written Objective-C and Java at my former employer, I much prefer writing apps in a more terse language like JavaScript despite its many foibles.

The interpretive nature of JavaScript also significantly shortens the RN app dev cycle, making it as easy as developing web pages. Reloading a RN app in a second by pressing ⌘+R turns out to be a truly refreshing experience. (You do need to recompile the XCode project when you switch between build targets, link in a new native module, add a resource file, patch an Objective-C implementation, or resolve the occasional red-screen-of-death.)

Another design choice that facilitates quick UI iteration is React Native's flexbox and styling abstraction, modeled after a carefully chosen subset of CSS features. Layout tweaking using the flexbox model rarely gives me any unpleasant surprises, unlike my traumatic experience grappling with Interface Builder's constraint editor.

App performance

React Native app's UI components feel native because they are native controls exposed to JavaScript via a JS/Obj-C bridge. Achieving the same level of look-and-feel in HTML is a sisyphean task — eventually you'll have to either compromise on fidelity or resort to a non-standard UI theme.

React Native borrows the virtual DOM diff idea from React and makes it conceptually simple to write high-performance UI. If you try to repaint a full-screen background 60 times per second, RN will stutter; but for most non-game apps with few moving parts, it's not hard to create a smooth experience.


Cross-platform support

Facebook finally unveiled React Native for Android yesterday, almost six months after the iOS release. However, porting my RN app to Android is non-trivial. First of all, some of the UI controls such as SwitchIOS need to be replaced with Android counterparts; some (e.g. ActionSheetIOS) must be scratched and redesigned for the targeting platform. A more pressing issue is porting all of the native libraries my app depends on. I'll end up writing Java extensions or waiting for others to do it.

There's also no obvious way to write Apple Watch apps in RN yet.

Library support

React Native has fewer than 30 built-in components so far, iOS and Android combined. Chances are good that you'll need to find (or write your own) extensions to implement some basic features, for example, accessing SQLite databases or supporting in-app-purchase items. You'll be hurled back to the Dark Ages of app development, so be prepared with some knowledge of Objective-C and Java. Fluency in native code will be useful anyway even if you don't write RN extensions because: (1) React Native's documentation isn't on par with Apple's yet. You'll sometimes need to dive into the .m files to ferret out implementation details. (2) React Native is still a young framework, fraught with bugs on the other side across the JS bridge.

ES6 language support

Although you can use ECMAScript 6 features in your RN app, be aware that when you run react-native bundle --minify for release build, RN transpiles JavaScript into ES5 using Babel before calling UglifyJS2 for minification. However, not all ES6/7 syntax get transformed, and UglifyJS will choke on statements like for (... of ...), yield, etc. This is not technically a RN issue, but it will bite you during the release phase if you go too fancy with ES6 goodies.


I find React Native a good fit for JavaScript programmers to develop decent native apps with mostly standard UI. This fledgling framework has shown great promise to reduce app development cost, posing a real threat to Cordova and Appcelerator's Titanium.