My name is Alex Androsov, I have been working in Yandex as a front-end developer for many years. Two years ago, I and my partners had the idea to create a mobile social network
Verb . Verb's idea is that users can share small statuses - “willows” - about what they are doing at the moment, simple things that you want to tell your friends about, but there is no place to write about it. And we have even received investments, but now this is not about that. Today I want to talk about how and why I wrote a mobile application on react-native.
I have a backend developer background, more than 10 years of web development experience, but creating a mobile application for me was a completely new area. What to do in this situation? Quickly learn Objective-C or Swift for iOS and Java for Android? In parallel, writing two applications at once seemed like a bad idea, I alone clearly could not quickly implement all the ideas on two platforms. Therefore, I began to look for options for cross-platform development.
By the way, there was a sensation around React, react-native appeared. Then I wanted to try it. Looking back, the choice of react-native fell, by and large, not because of some objective reasons, but rather because of subjective ones: there were already PhoneGap (WebView in JavaScript, CSS, HTML), Xamarin (C #) before it. and NativeScript (JavaScript, TypeScript, Angular).
I already had experience with PhoneGap and didn’t want to use it (I already really bought native components instead of implementing them on web technologies), I didn’t know C #, I didn’t want to write to Angular, so the choice fell on RN.
')
Like NativeScript, RN has bindings of native components in JS, a similar work system (we’ll talk about this later) and features.
The first version we started with was 0.7.1 (current version is 0.46), my first commit was July 21, 2015. There was no Android support at all. She appeared only in September 2015 (0.11). At the same time, it was the “initial support” of the platform with a bunch of problems and flaws. It will take a long time before iOS and Android support becomes more or less equivalent in react-native.
Looking ahead, I’ll say that at some point we decided to write the
Android version in Java. The application was already needed, and RN was not ready at that moment (currently there is no such problem). But the
iOS version of Verb is completely written in react-native.
What is react-native?
So, react-native is a framework for developing react-based cross-platform apps for iOS and Android. React is used here as an idea, not an implementation: JSX, component approach, state, props, component life cycle, CSS-in-JS.
If we draw an analogy with the usual web development, here:
- no HTML, but there are native components in JSX (<View />, <Text />, <Image />)
- no css. All styles are written CSS-in-JS, layout is built on a polyfile for flexbox (while it is slightly different from the standard, for example, the flex-direction of the default column, rather than row).
- no familiar DOM API. No window, document and all that. From the usual API only GeoLocation API (navigator.geolocation) and XHR
The layout of the component looks like this:
render() { return ( <View style={ styles.container }> <TouchableOpacity onPress={ this.props.onPress }> <Image source={ require('../icons/close.png') } resizeMode="cover"/> </TouchableOpacity> <Text style={styles.placeText} numberOfLines={1}> { myText.join(', ') } </Text> <ScrollView keyboardDismissMode="on-drag" refreshControl={<RefreshControl/>} /> {this.props.children} </ScrollView> </View> ); }
To make it easier to understand, I will give an analogy with familiar HTML. <View /> is <div />, <Touchable * /> - <a/> (there are several of them, with different reactions to pressing), <Image /> - <img />, <ScrollView /> - something like <div style = ”overflow: scroll” />
CSS looks more familiar:
const styles = StyleSheet.create({ default: { fontSize: PixelRatio.getPixelSizeForLayoutSize(7), color: 'rgba(0, 0, 0, 0.60)' }, suggestUser: { height: PixelRatio.getPixelSizeForLayoutSize(100), backgroundColor: '#FFF', shadowColor: '#000', shadowOffset: { height: -5 }, shadowRadius: 5, shadowOpacity: 0.5 } };
StyleSheet declares and compiles styles, they are immediately directly transferred to native, so as not to chase each time. PixelRatio is needed to proportionally increase the size of elements depending on the screen.
How RN works
If this is a
great article from Tadeu Zagallo on RN guts, I’ll tell you in short about its essence.
There are three threads in iOS:
- shadow queue - queue processing and rendering layout
- main thread - components work here
- JavaScript thread - JS works here
The general scheme of work is as follows: JS (essentially React) is executed, the result of the work must be transferred to the native code. To do this, there is a special bridge that transmits a set of instructions using JSON. RN executes them and renders the native components of the platform. The result of working through the same bridge can go back to JS.

All communication is asynchronous. In this case, the bottleneck is directly the bridge, serialization and deserialization of data. Hence the interesting features:
- Sending large data packets of JS <-> native is a bad idea, it will slow down
- Doing great JS actions is also a bad idea. This will lock the threads and slow down the rendering, no 60fps will work.
- Doing frequent actions (for example, animation or scrolling control) on JS will not work either, it will slow down.
Total, the general rule: do not forget that we are working with native code, and not JS. Everything native can do should be native.
Write once, run everywhere?
Not here it was). In fact, the paradigm is: learn once, write everywhere. Why is this so? Everything is native, so forget about the full cross-platform. The platforms are different, so the native components are different. They have different logic of work and interaction mechanics. This mainly concerns the navigation and user interaction components. Therefore, at the beginning of development, it makes sense to immediately distribute the application with the basic screens and transitions. The difference ends there; all the internal components are likely to be the same. Convenience is added by the RN itself, the entire platform-specific code can be divided into the component.ios.js and component.android.js files, then each platform will have its own version without any if inside.
iOS version of Verb inside
Inside the application is written on react-native + redux. Redux was useful, by the way, not only as a good library for organizing work with the state of the application, but also for communication between components. RN provokes writing pure components without side effects or using global objects, therefore communication of components through a common state is almost the only normal way.
Plugins:
- React-native-deprecated-custom-components - I use the old Navigator, because not yet moved to new react-navigation due to a lot of bugs
- React-native-device-info - information about the UUID, device version and locale
- React-native-fbsdk - FBSDK Bridge
- React-native-imagepicker - my own binding over ActionSheetIOS, CameraRoll and ImagePickerIOS for uploading photos
- React-native-l20n - localization with l20n
- React-native-linear-gradient - implementation of gradients
- React-native-pagecontrol - my binding in UIPageControl
- React-native-photo-view - a simple library to make full-screen viewing of photos
- React-native-svg - svg binding
- React-native-vkontakte-login - bridge in VKSDK
Statistics:
- react-native-fabric - a bridge in Fabric and Crashlytics
- React-native-google-analytics-bridge - bridge in GA
- React-native-sentry - collecting kreshy and sending to own installation of Sentry
- React-native-bugsnag - BugSnag Bridge
When collecting kreshy, the most important thing is to get stacktrace from JS. Fabic does not know how, in the Sentry better, BugSnag turned out to be the best. But we still decided to move to Sentry so that all the problems were in one place.
We also use geolocation and pushes. React-native has everything you need for this.
The important part is performance. As I already wrote, the bottleneck in RN is the JS <-> native bridge, so the problem of reducing the number of redraws becomes full length. It follows that all the best practice tips from react and redux are very important. React.PureComponent or shouldCompomentUpdate, less connect-components, flat data structures, immobility - everything gives a good performance boost.
Unevident advice
No need to delay the update version. Previously, when the RN was released every 2 weeks and almost every version had incompatible changes, this advice was very important. For 1-2 months, the framework could change very much, so it was very difficult to update immediately for a couple of versions. Now the situation is better, releases once a month, the framework no longer changes so much. But as before, I am updated as soon as the new version comes out.
The unification of the react-component (the designer’s help will be needed here) makes it possible to very quickly develop new screens. In general, the component approach and the fast linking of components is a good piece of both react and react-native.
The boilerplate for creating new screens in rn + redux is big enough. As in react + redux, rn + redux will have to write a lot of code to create a new screen: create a screen component, register it in Navigator, write actions and reducer to go to the screen. Plus, the standard boilerplate for data processing for the new screen.
Do not write everything in JS. The application should be written as close as possible to native, look for the bindings in the required native components, or write them yourself. I assure you, this is not difficult at all.
We must participate in the community. The RN has enough bugs and flaws, but there are no problems to fix them. Maintainers are actively involved in PR. However, it is often necessary to fix bugs in the native code itself, so Java or Objective-C will have to be learned. All my PRs have accepted. For example, I fixed a few bugs in the camera or upload photos to the server.
Conclusion
Writing on react-native was convenient, quick and pleasant. It really allows you to quickly create prototypes of applications and bring them to release. Technology is young, so there are typical problems of early adopters (for example, periodic incompatible changes). But with each release, RN is getting better and more stable, Facebook is putting a lot of effort into it and relying on it. To date, part of the Facebook application is already written react-native, and Android support has reached the level of iOS.
I have worked enough with the technology and I can say that it’s quite realistic to write a not too large iOS application, similar to Twitter or Instagram. Unfortunately, android didn’t try to make a deep attempt, so I can’t say it, but I hope that in the future we can try to compete with our native iOS version.
And we are looking for a remote developer for part-time! Write to doochik@ya.ru.
useful links