React Native (RN)
I think every mobile developer should have heard of it, but what is it really and is it really a game changer?
A framework to build UI
React Native is a UI framework created and mostly maintained by Facebook to create cross-platform mobile applications using javascript.
Why is it different from other hybrid applications?
The main difference from other frameworks like Cordova, Ionic (btw Ionic is just Cordova+AngularJS) is that the UI is rendered using real native components and not as an html page.
Is it really much better?
Well, using native components allow animations, scroll, loading, ... without experiencing glitches like you could have with html rendering.
Are applications built with it really fast?
The answer there is... not really yes and not really no, they could seems to be fast for some basic features, like scrolling, but behind the scene it is not as simple as it looks like.
The objective of react native creators was to ensure a 60fps, that is to say, to ensure the screen is refreshed 60 times per seconds. The objective wasn't so that those 60 screen render by seconds would produce different results. As the matter of fact, if the screen refresh rate is good, the content refresh rate isn't so great.
Event handling in a purely native application
A native application use an event loop in a main thread :
- wait for an event,
- handle an event, if any, (with native code)
- refresh screen...
... and then go back to wait for an event...
Event handling in a native application
First of all, you need to understand that a React Native application :
- uses at least two main threads, one for UI display and one for javascript,
- have two UI representations, a virtual one in JS and a real one with real native components
Except for native UI Modules, that can provide their own native code for handling events, in React Native it is more like this:
- On event loop
- wait for a native (like a screen touch) event in native part
- forward the event to the JS Thread, using a bridge
- refresh screen
- On javascript thread
- wait for an event (forwarded from event loop, or javascript event)
- process the event
- refresh the virtual UI representation
- use a bridge to update the native UI representation if necessary
Conclusion about RN application speed
Yes, screen refresh rate is quite good as there should be no excessive computation on event loop, only event forwarding.
No, content refreshing isn't fast at all, but it should remain fast enough for most non-game related applications.
A component based approach
A RN application is build by writing components, if we were to compare it to a MVC approach (Model View Controller), RN write all three parts in a single class.
As most of you should know, the MVC approach isn't really the better one for writing mobile applications.
I tend to mostly use the MVVM approach even If VIPER has its own merits.
Pro: it is quite efficient to write simple applications
With a component based approach you can quickly write simple applications, one component by screen. If one screen is two complicated, just create sub-components to handle it's different aspects.
Con: RN alone is really bad for complex applications
If you use React Native by itself, without any library, communication between components can be a nightmare.
Let's say you have a main component A with two sub components B and C. The only way for B and C to communicate would be by putting some forwarding mecanism in component A. What about if the tree is even more complex?
Fortunately there is an OpenSource library, called Redux, that can help with that, by creating what we could consider as a shared model.
As components can automatically respond to changes on this shared model, and as they have means to send changes to it, different components can "communicate" through it. That is to say component C can respond to changes to the shared model asked by component B.
If libraries exists, why do I consider RN to be bad for complex applications?
First of all, using libraries tend to be a bad thing, especially when they are written by distinct third parties.
Ever heard of dependency hell? Libraries have there own dependency and two different libraries might share a dependency for a third one, but with different versions.
Having to rely on third party plugins and libraries have always be the worst part of hybrid applications and RN isn't better than others on this point.
RN developers tend to do most business work on components
Well, I can't say I have such a long experience on writing RN applications, but I have seen enough tutorials and code examples to know how RN developers tend to do things.
What most developers do:
- call APIs and perform business code directly from components,
- handle APIs result inside the component.
Those are habits of web developers, not of mobile application ones.
Why is it bad?
- you should handle the case where API result arrive after the component is unmounted,
- you can't have already prepared data when the component mount
Don't worry, there are solutions
I have had to work on a project (for work, not a personnal project, I don't care being Android compatible on personnal project so I only use native programming) where I had to communicate with an external device.
Many components would report different informations retrieved from the same status fetch call, so it wouldn't have been pertinent to have those components perform there own status fetch call.
What I appreciated about Angular on the Ionic applications I had to work on, was the capacity to create services and the dependency injection system, with that in mind I started to work on this project.
What I did: [this part is intended for RN developers with some knowledge about Redux]
write components with hardly any business logic in it, they can call service methods but does not handle the result
use redux to store most informations needed by the application, reducers would be there only to update the store state, not to perform processing
divide the business logic in different parts, each part having :
- a redux reducer to update the store
- a service which would perform all processing elements (like calling an API) and then store the result in redux by dispatching
Service processing can be triggered:
- directly (ie, like by pushin a login button),
- in response to a store change
To let you understand the reason of the second trigger mecanism, I had to write a service to poll the external device service. This polling requires knowing the IP address of the device. Should this service worry where this IP address is comming from? The answer is NO, it should only do it's job, on a KISS (Keep It Simple, Stupid) way. Should this service care about who will use the retrieved status? NO, it should just dispatch it to the redux store.
I was also ask to use SSDP to try automatically getting this IP address from the device itself, so I created a second service, that would just handle the device detection. Should this service care about who/what will use the IP Adress? The answer is still NO, KISS.
In the end, how does it works?
The status polling service would listn't to changes on an ip
property on the redux store, without caring at all where the value is coming from.
The network discovery service would dispatch an action to update this ip
property without any concern on who/what will use it.
Components retrieve status related informations, not directly by the service, but by connecting to redux. When a data used by the component is updated, redux trigger the rendering mecanism of the component.
Should you use it?
As always the answer isn't black or white.
If you :
- absolutely need to be compatible with Android AND iOS,
- AND have not a huge business logic to implement,
- AND have a quite simple UI, without lot of animations.
Well, RN might be an answer for your need.
In the converse, if you:
- target only one platform,
- OR have an application relying on expensive business logic processing (like my SolvoKu application),
- OR want to have very smooth complex animations,
- OR need to react really fast to touch event,
Then NO, don't use RN, don't even think about using an hybrid approach.