Building a Native Soundcloud Android app with React Native and Redux

Seven months ago, React Native for iOS came out. I built the ShenJS app for the 2015 JSConf China the day after the release. It was more out of curiosity than anything else.

At Wiredcraft, we’ve also been building apps with the Ionic framework (Cordova + Angular.js) for one of our clients, so it’s only fair that I compare these two.

Working with Ionic

Write once, run everywhere

Poor performance with complex components (e.g. Google Maps)

Toyish

Note: The apps we built were iOS only - I have no idea how it plays on Android.

Mostly, we were kind of bummed by the performance. Before React Native for Android came out a few weeks ago, we had been building web and Windows (desktop) apps (really) with React (and Electron) for the Myanmar elections, so I got excited about giving React another try.

Our team is very comfortable with React + Redux, and I happened to find the soundredux project by Andrew Nguyen. It’s a great app and I’ve been using it instead of the official Soundcloud client for a week. I liked it so much that I wanted to make it work on Android.

So instead of introducing explicit if/else checks for the platform, we tried to refactor platform-specific parts of the UI into separate components that would have an Android and iOS implementation. At the time of shipping Ads Manager for Android, that approach yielded around 85 percent reuse of app code.

Here’s a diagram that explains how the whole thing works:

After spending some time on it, I found there was still a lot of work that needed to be done, either by improving my own code or Facebooks’s design on their thread system (here we are talking about the UI thread which has a direct impact on the user experience).

Since we’re using redux in the app, and for each scene, I have a mapStateToProps method which connects the needed data to each component container (to avoid having to pass every props from the root component all the way down - this could save a few rerenders because not all components need the whole state tree).

When the user clicks a song from the song list, a few actions will be triggered.

And in the playSong function I will need to dispatch the playSong action which will change a few states in the redux reducer (with lots of calculation and network request). After that, I will navigator the screen to the Song scene which will show the user the detail view of the current playing song.

If I leave it like this without doing anything, when the user touches the screen to play a song, the TouchableOpacity component will have a noticeable lag and the opacity effect won’t kick in until the dispatch operation is finished. In other words “Dropping JS thread FPS because of doing a lot of work on the JavaScript thread at the same time”.

So what I can do here is use the InteractionManager to postpone a few actions and let the animation finish first and then do the other operation, so the user won’t feel the lag from the UI.

Writing CSS with flexbox is easier than normal CSS (for me personally because I’m bad at it) and you don’t have to worry about browser compatibility

Building a native module for react-native is simple and straightforward thanks to Facebook’s nice design

The Soundcloud API is awesome

The good and the bad

The bad first, and then the good will make it right :D

Bad:

Ecosystem: There’s not enough modules (yet), especially for Android.

Documentation: Still needs to improve, UIExplorer is a good place to start.

Performance: Animations and slow navigator transitions as mentioned in the performance page on the official documentation website

Note: I’m pretty sure the performance is something that could be fixed by improving my own code, and this is part of the reason that I’m sharing this with you. If you have any experience or suggestion, I’m all ears. Either a pull request or a new issue in the repo would be great!

Good:

Good community and ecosystem. No wonder the React communutiy is one of the best and active open source communities.

Code reuse, from the Web. If your project happens to use React for the web part, you can reuse lots of code for your mobile client.

Wrapping native modules is easy, so when there’s not enough modules or you have a performance issue, you can write your own and contribute to the ecosystem.

PS: As a JavaScript developer without any Java programming experience, I made this Couchbase-Lite binding for react-native at weekend react-native-couchbase-lite. It’s fun!

Conclusion

As you are reading this post, there’s a chance you may be wondering whether or not react-native is right for your next production project. This is not the purpose of this post and I do not have a clear answer. I’ve been enjoying the process and learning React Native helps me in many ways. I suggest that you check out what other people are doing:

React Native official showcase page - A list of apps using React Native.