
Tempted to Abandon React Native for Native Android - silkodyssey
https://kelvinpompey.me/tempted-to-abandon-react-native-for-native-android/
======
htormey
To summarize this article: The author really enjoyed using React Native up
until he hit some performance issues related to loading large images on
certain versions of Android.

He doesn't go into what specifically the performance issues were, any
techniques he used to profile his app, what third party libraries he tired or
anything.

Performance issues happen all the time with native apps that don't use React
Native. Optimizing is a core part of what a software engineer does. Giving up
on weeks of learning without a good reason seems like a poor choice to me.

As it so happen's I have been working with a colleague of mine who just fixed
a React Native performance issue relating to images on Android on older
devices. The author might want to check out the following article:

[https://facebook.github.io/react-
native/docs/performance.htm...](https://facebook.github.io/react-
native/docs/performance.html#moving-a-view-on-the-screen-scrolling-
translating-rotating-drops-ui-thread-fps)

Our particular issue was solved by the following:

"This is especially true when you have text with a transparent background
positioned on top of an image, or any other situation where alpha compositing
would be required to re-draw the view on each frame. You will find that
enabling shouldRasterizeIOS or renderToHardwareTextureAndroid can help with
this significantly."

Apart from the above, this article is pretty shallow, which is sad because I
would love to read a good article on React Native's performance. Perhaps I
will write one if people are interested.

~~~
cel1ne
I analysed react-native's performance issues with images and out-of-memory-
errors a while back.

Their (and their image library Fresco's) problem is that they make heavy use
of object-finalizers, which is an error in Java and especially Android.

I reported a couple of bugs, but got dismissed:

[https://github.com/facebook/react-
native/issues/8711](https://github.com/facebook/react-native/issues/8711)

[https://github.com/facebook/react-
native/issues/8780](https://github.com/facebook/react-native/issues/8780)

[https://github.com/facebook/fresco/issues/1363](https://github.com/facebook/fresco/issues/1363)

I found this rather frustrating.

I also found out that using plain java-serialization/string over the JS/Java
bridge is twice as fast compared to their homegrown memory-management written
in C. Again, a bugreport, again, dismissed.

[https://github.com/facebook/react-
native/issues/10504](https://github.com/facebook/react-native/issues/10504)

It seems that Facebook's Java programmers don't know Java very well.

~~~
BoorishBears
Fresco is _extremely_ notorious for causing crashes, I had no idea React
Native used it. Picasso and Glide are the two sensible choices for image
loading.

Facebook's tools for Android are generally written in a way that you get the
feeling one could only justify by repeating the manta "We're Facebook, these
are Facebook scale problems" the whole time writing you're them. (see: Redex
vs just Proguard)

Wether they 're problems worth solving again need not be evaluated.

~~~
quotemstr
Redex does tons of things Proguard doesn't, and it operates on Android's
native Java-program format, dex files, not java class files like Proguard.
What's the problem?

~~~
BoorishBears
It's diminishing returns, it breaks in many more ways than Proguard with
minimal benefit. I truly question if focusing the engineering effort on
reducing bloat in their app won't have saved more space than Redex.

~~~
indy
"it breaks in many more ways than Proguard" is a phrase I thought I'd never
hear

------
t1amat
I've been playing a lot with React Native over the last year; professionally
for almost 4 months now. This really aligns with my experience. I don't share
the same opinion of going back to native code though.

This really is a fantastic platform. You really can, today, write native cross
platform and web apps with the same code base. With few exceptions, everything
from including native modules to upgrading is painless. The UI metaphor is
fantastic, the tooling is superb, the editor support is there, the community
is growing. It's a great place to be.

It's not without it's warts though. From my experience, the real problems stem
from the 3rd party native modules. It's not even their fault, the platform is
just moving so fast. As recently as the 0.40 release, every native module out
there was broken on iOS for a short period of time. I was the first to submit
PR's to two fairly widely used ones, and that was multiple days after the
release. On this point, I believe this is more indicative of a community that
generally doesn't upgrade their projects right away- a combination of painful
prior experience and a deep seeded distaste of having to re-release their app
on all stores as you can leverage a tool like Microsoft Code Push to change
the bundle as long as it is compatible with the native shell.

Of the two RN projects I'm working, both have at least one dependency pinned
to a Github fork I have of a project, waiting for my patches to be released.
This sounds worse than it is, as the majority of native modules are
hilariously small and easy to modify, but it still is worth mentioning as a
point of friction today. As the community grows, I expect this will diminish.

~~~
htormey
Yep, exactly my experience. I love React Native but if your not used to the
Javascript style of million's dependencies your in for a world of pain.

It's critical to spend more time vetting third party React Native/Javascript
libraries as the quality level varies way more than with native libraries.

As a native developer I hadn't spent a lot of time working deeply with npm.
One thing to be careful about when saving packages to your project is the use
of ^ versus ~. See:

[http://stackoverflow.com/questions/22343224/whats-the-
differ...](http://stackoverflow.com/questions/22343224/whats-the-difference-
between-tilde-and-caret-in-package-json)

" the tilde matches the most recent minor version (the middle number). ~1.2.3
will match all 1.2.x versions but will miss 1.3.0.

The caret, on the other hand, is more relaxed. It will update you to the most
recent major version (the first number). ^1.2.3 will match any 1.x.x release
including 1.3.0, but will hold off on 2.0.0."

Considering the volatility of some third party Javascript libraries, this can
cause quite a bit of pain.

It's worth doing the following in your home directory add save-prefix=~ to
your .npmrc and all npm install's in the future will automatically add ~
instead of ^

~~~
cageface
I recommend pinning to exact versions and using a tool like npm-check-updates
when you want to upgrade to newer versions of libraries. We had a lot of
problems with breakage due to different developers having slightly different
versions of dependencies.

React Native is a great platform but it's still very fragile, particularly on
Android.

~~~
Matthias247
I recommend that too. I only used the npm ecosystem for a short time, and
still had dozens of silent breakages from libraries which were expected to
update in a backward compatible fashion. And even if a dependency itself is
pinned to an exact version, it might be that the transitive dependency of this
thing changes and breaks. npm shrinkwrap and yarn are supposed to fix that.

------
grandalf
I've done some work with react native, and have definitely been disappointed
by the poor quality of many third party libraries that are not supported by
Facebook.

This is a big opportunity for those who might wish to make a name for
themselves by developing some top quality open source components, but I also
think Facebook should do a bit more to make using the phone's core features in
a very high quality way as easy as possible. Things like the camera, audio
recording, video, etc., are handled only via third party libraries.

The third party open source work is improving, and I'm grateful it exists, but
much of it lacks contributors. Many have large lists of unresolved issues on
github.

It would be very smart choice for Facebook to put a dozen or so developers on
the task of submitting high quality PRs for the top 20 open source non-
facebook libraries.

------
nurettin
I searched for the holy grail of cross-platform goodness like a fool for
years. I now have my first native UI android application on google play and I
don't regret the decision. I made a prototype and then optimized it in ways I
wasn't able to do in html or react-native. (try downloading and caching
pictures rendered in a listview asynchronously while keeping the scroll
smooth)

I now don't have an iOS version, but in my opinion having a finished product
that is already gaining traction makes up for the lost time of learning to
make the same thing for iOS.

~~~
menckenjr
There really is no such thing as a free lunch. If you want to skip having to
learn the native platforms, you're going to have to put up with your app
having at least one giant external dependency in it.

(Native iOS app developer here, dabbled in React Native and went "nope" as
soon as I saw how it worked and how heavily it depended on 3rd party
components.)

------
hammerandtongs
My next foray into mobile is going to be with this-

[https://www.nativescript.org/](https://www.nativescript.org/)

Digging through the api it just looks much more capable in directly calling
android instead of abstracted cross platform blobs.

~~~
kartickv
The NativeScript site says that I can use their cross-platform wrappers like
Button, which delegates to UIButton on iOS and android.whatever.Button on
Android. So far, so good. But suppose I now want to invoke some method on
Button that exists only on iOS. Can I do that? If not, it's the least-common-
denominator, which I'm not interested in using to build an app. I'm thinking
about something like:

var button = new Button(...);

// Set the common properties:

button.backgroundColor = ...;

button.text = ...;

if (iOS) {

    
    
      // Set iOS-specific properties
    

} else {

    
    
      // Set Android-specific properties
    
    }

~~~
dbbk
Yes, it literally works like that. See the docs:
[http://docs.nativescript.org/cookbook/application](http://docs.nativescript.org/cookbook/application)

The variable is app.ios / app.android

------
ed
Sounds like a good opportunity to build some performance-tuning muscle :)

Whether using RN or java, you'll want to know how to debug memory/performance
issues on Android - they're mostly unavoidable on mobile devices!

(And maybe you can file some issues against React Native, too, which would be
great and help the platform)

~~~
silkodyssey
That's a fair point about the opportunity to build some performance-tuning
muscle but I imagine to do that would require solid knowledge of both React
and Android. Where do I start? I am more inclined to go towards the native
Android side first.

Aa a follow up, I just did a test with a native Android app doing the same
thing: getting an image through an Intent. With the native Android app, the
same image that was crashing the React Native app doesn't cause any problems.

~~~
Gudin
What does that have to do with performance? You shouldn't serialize hi-rez
bitmap and pack it in Intent.

Activities/Intents should at least force you to be careful and not to keep all
data around in your memory, but only pass data you really need.

------
Hydraulix989
It'd be nice with React Native was actually "native" and not just a JS
interpreter (really not that much different than HTML5 running in a browser).
No wonder there are performance issues.

~~~
ec109685
With ReactNative, the controls are all native, JavaScript is just there for
orchestration, so it is far different than HTML 5, given the browser doesn't
give you the same array of native components to use.

~~~
2sk21
I haven't been following React closely but this reminded me of a package
called SWT that is used as the underpinning for Eclipse
([https://www.eclipse.org/swt/](https://www.eclipse.org/swt/)). In the case of
SWT, the underlying widgets are platform native but the orchestration is in
Java. SWT was used to build a few desktop apps but mostly it seems to have
been forgotten now. It left me skeptical of these kinds of thin UI layers.

~~~
mateuszf
I'm not an expert, but I think that there is a different approach between
React / React Native and SWT. SWT created layer of abstractions - when using
their apis you were writing code once - and it was supposed to work the same
way on all supported platforms. However React / React Native just use the same
React paradigm to rendering controls, but the controls themselves are specific
to the platforms. What you share is all the code that is not views, but views
themselves are separate codes.

~~~
Hydraulix989
I've been working pretty extensively with RN these days.

Almost always, the code is the same (doesn't HAVE to be though but almost
always is), and even the views are the same (barring some exceptions where
Android and iOS have completely different design language requiring you to
customize things at the code level using platform conditionals in the same
source file).

------
teyc
If you already know how to do the image related task in Native Android, you
could spike a test project and verify that it's performant on the smaller
devices and the problem could be attributed to React Native alone. Then it's a
matter of porting the high level API to JS.

Given that you believe this is a memory-related problem, perhaps it's because
the image is too large to fit into the available memory, and having React
Native made it worse.

~~~
silkodyssey
I did just that. I created a native Android project that selected an image
from the image picker and displayed it in an image view. I tested it with a
few images and it worked. Even the image that crashed the React Native app.

"Given that you believe this is a memory-related problem, perhaps it's because
the image is too large to fit into the available memory, and having React
Native made it worse. "

This is precisely what I think it is.

~~~
tomwilson
Seems like it can't be that hard to use that native code you wrote in your
test in the react-native app though. Write the final image to disk. Load the
image in an image view. Never pass the data through the JavaScript bridge.

------
EGreg
What do you all think of Cordova? Do the author's comments apply there also?
Does it crash from using too much memory after a while of loading objects? And
does it make things not work on older devices and platforms making it a
dealbreaker for anyone?

~~~
mercer
My recent experience with Cordova has been much better than I expected. It's
quite a bit easier to work with than I thought, and the performance is fine
for the relatively 'standard' UI and animations/transitions I needed. And with
a few specific tweaks I could even make it seem pretty native (momentum
scrolling, etc.).

All that said, I'd still recommend going native or React Native if 1) you can
afford it (time/money/properly skilled employee), or if 2) the app's needs are
beyond what a 'typical' in-browser web app does.

In regards to the latter I've found quite a number of plugins that let you do
notifications, or use the accelerometer, but on the whole I've found that
cordova plugins can be finicky. Plus, the more plugins I need to add and the
more native functionality I need to use, the more nervous I get about not
fully grasping the underlying stuff.

Basically, I used to think Cordova was never really an acceptable option,
especially with the release of React Native. Now, I think there are plenty of
situations where it's the best solution for a client.

------
silkodyssey
I posted a follow-up to this story talking about further explorations based on
the feedback I got from your comments.

[https://kelvinpompey.me/tempted-to-abandon-react-native-
for-...](https://kelvinpompey.me/tempted-to-abandon-react-native-for-native-
android-part-2/)

