At Tiki, we have been developing new features for our Android and iOS app, in React Native. If you’re evaluating React Native for your next project, or just curious about it — here is our story. In this article, I will share our overall experience with RN, and the things we have learned so far.
Why React Native?
Hot reloading & Live reloading
We love the live reloading capabilities in React Native. In native languages, we have to wait until the completion of compilation up to
React Native also has a feature called Hot Reloading. It keeps the app running, and injects the new changes in realtime. At this time, hot reloading is not working perfectly in a few situations, but a reload of the whole app, usually fixes it.
Incremental adopting React Native
We started using since early 2016 for experimental feature like picking attribute for a product.
Because converting completely to React Native comes at very high cost for us; plus some features requires native performance. We decided to become hybrid app.
Our business held an annual event, named “Dzut Co Hon”, on the web to express gratitude to our customers as usual. However, last July the event also took place on mobile. Brief description about the event on July in the lunar calendar, in many countries like Vietnam, China, HongKong, people give things away to pay homage to the death. At Tiki, we slashed our price up to 80% instead of giving. All users need to do is tap on the expected products. The quickest the winner.
Because of up to 60k concurrent users at a time, fixed schedule for events. We had no time for bugs fix, Appstore and PlayStore approval process. React Native came to the rescue.
Problems we faced
Frequent Release cycles
React Native is in active development. There are many features, and bug fixes in each release. But every release often brings breaking changes as well (maybe in a “move fast and break things” spirit specific to Facebook). In these cases, because we have a few features using React Native, we have to spend a lot of time fixing things, bundling while upgrading new version.
Slow page transition
After hitting the sign-in button, we move to the next screen right off the bat if the event was happening.
InteractionManager.runAfterInteractions(). Before we made the transition, we pre-loaded all the tab data, and product lists on the
Register Screen. Once the transition was complete, we just focused to render the content. It helped us provide a smoother experience to our users.
When our QA team tested count-down functionality. A very strange bug was filed. iOS count downs faster than Android does. We tried to solve problem with an experiment.
currentTime2 — currentTime1 = 10000 on both platforms. However, it’s just true on iOS. In addition, iOS rendered the product list as above much faster than low-end Android devices did. We had to handle with a little trickery.
const platformDelta = Platform.OS == 'ios' ? 1000 : 1600;
let diffInMillis = new Date(endTimeInMillis).getTime() - Date.now() - platformDelta;
“Dzut Co Hon” was initially based on Redux. What we expected was to click on the product, it should have immediately shown a progress on it and instantly changed to selected state after network call. In reality, it took us a second even more when multiple products were tapped. After having investigated, we noticed that it took much time for
Reducer to receive multiple dispatched
ProductComponent . We decided to use
ProductComponent and leave Redux out in
As for our new app home where RN 0.42 is used, ListView is still a huge issue for us because of our large, complex multiple view types and tabs.
It feels janky when scrolling. We will convert to
FlatList soon to see how it goes.
As for multiple tabs with
ViewPager, when all the tabs are loaded, all
ListViews and the whole
Store are kept in the memory .
OutOfMemory occurs often on low-end devices. We have to retain data only for the active tab in
Store . Data for other tabs is pushed and persisted on
LocalStorage . Put it another way, other tabs have nothing to render but a loading view. . When users back to the previous selected tab. It only takes time to retrieve from disk cache and render.
We make great use of
PureComponent. When users slide a banner, a deal…, the indicator is changed. Consequently, its parent and maybe the whole component tree must reconcile causing performance hurt. Implementing
shouldComponentShouldUpdate() to make sure other components won’t be affected.
At Tiki we use Jenkins to deploy native apps to staging or production environment. While developing with React Native we want to have the same development process. When a commit is merged to the staging branch, tests are run and Jenkins pushes the latest JS bundle to CodePush server, then notifies us via Slack channel.
Based on a sample, we wrote a custom CLI tool to run
code-push release-react "TikiHome-ios" ios -d "Staging" — des "Jenkins deploy" — dev true -m false -t . Once the dev branch is good to go, we merge the code into the master branch. Jenkins runs all tests, builds a production target, deploys the latest bundle, create a tag version.
We strongly believe that React Native is a fantastic framework. While it does have a few issues, those issues are overshadowed by the mountain of benefits you get from using it. We’re happy with the choices we’ve made — they’ve allowed us to move much more quickly on our mobile products.
Author: Daniel Le – https://cuong-le.medium.com/