Tame the beast. What did we encounter when developing an application for keeping a personal journal on React Native
In the previous article, I described in detail our experience in creating a web service / mobile application for keeping a personal diary. The current version of the application (the minimum efficient version is already available on Google Play) is being developed by React Native, and here we will dwell on it in detail today.
We talk about our own experience of working with the framework, ways of expanding the functionality, “pitfalls” (where can I go without them!) And how we got around them.
A little bit about the hero of the occasion - React Native . He is still good!
For those who know enough JavaScript and especially NodeJS - it is very good. If there is experience with React, well, or at least there is an understanding of its idea, mechanism — it is simply great!
The main thing is that the output is a truly native application. Extensions and plugins cover almost 99% of typical tasks. The remaining percentage, if absolutely necessary, can be added in native languages (java, object-c) and connected to the React Native application.
But enough about the pros, there’s zero point to them, even though the list will be impressive. All the buns and goodies are meaningless if the application does not start, and this is the first thing that “pleased” us React Native.
At first, he didn’t like the NodeJS version. Then the npm version. Then the Android SDK version, then the Android tools version, then ... It makes no sense to write about how all the problems were solved, since from that moment all of the above software has updated its versions and instructions will be irrelevant.
Just know: React Native's bottleneck is the build environment. Get ready to google, read forums and stackoverflow. As a result, they spent on deployment: Ubuntu - 3 days, Win10 - 2 days. Strangely enough, everything turned out to be simpler on Windows, well, or just on ubuntu, there were “bumps” and already understood what to do.
Note that someone will come in handy: the code below solved all the problems with the compatibility of sdk versions of the add-ons when compiling the project.
It is written in the /android/build.gradle file at the very end. Without this "directive", apparently, each of the plug-ins / extensions tried to compile on its own versions of the Android SDK, which resulted in building the project into a chaotic assortment of cruel mistakes and godless warnings. No one knows how relevant the recommendation will be in the future. But today, especially after Google forcibly forbade the use of the SDK below the 26th revision for compilation, this is very helpful.
The second “bottleneck” is pain not so much React Native, as, apparently, the whole of Open Source as a whole - limited support. The repositories are a bunch of unresolved issues. Fierce "smart" bots close bugs in the absence of activity, sometimes as many as 7 days later ... And everything seems to be fine. Nobody owes anything to anyone. Everyone is used to.

Patience burst when there was a "cant" with a banal text input in the usual TextInput. Just a text field. Just text input from the on-screen keyboard. After a couple of minutes of printing, the terrible lags and brakes of the system begin. They rushed to look for a problem - yes, there is one, it started with version RN 5x.xx Solve the problem? Not. Two or three issues on the topic just closed. A few more merged into one large .
I had to dig in, find out, try various options, change the RN version, in the hope that there was no such jamb there. As a result, by experiment, we managed to minimize dips in performance - we completely removed all the formatting and rewrote the input handler. But the unpleasant residue remained. The problem with the developers of the framework, by the way, has not been solved so far, six months have passed ...
Realm is a smart database, with impressive functionality and running on Android, IOS, Windows.
At first there was a double feeling, they say, you’re not ORM, there’s really no sql, the record is kept only inside the callback. Unusually and strangely, especially for a web developer hailing from PHP, which grew up on ActiveRecord and Doctrine. But in fact, it turned out to be very easy and fast to jot down your minimum set of functions for CRUD. And all questions of taste and habits were resolved by reading the official reference, brief, concise and understandable.
And then the carousel of gifts started:

It seemed that the question from the database is closed completely. We work! The case went on until it reached the search. Or rather, before full-text search. Even more precisely, before full-text search in Russian, case insensitive. He did not work. Totally. He worked in English. Case sensitive also worked. But without a register, but in Russian - even cry. After digging the help, bugtracker and the Internet, it turned out that the developer, due to certain technical reasons, was very inconvenient to “think” about supporting multibyte encodings and everything that goes beyond the Latin alphabet. Well, he did not. Why not?
There is nothing to do, I had to find a workaround. As a result of a brief assault, a “volitional” decision was made - we make a separate field “fulltext_index”. In it we duplicate all the text in the upper register, simultaneously “cutting out” unnecessary punctuation, unnecessary problems and all sorts of garbage. After that, it is logical to assume that we are doing a search with a forced upper register.
Victory! Search now works like a clock, even in Russian, even in English!
Total: despite the problems with the register, the database works really fast, convenience is on the level, a lot of ready-made chips are out of the box - in general, I recommend.
wix / react-native-navigation is a simple and stable navigator (a router, as a web programmer would say).
It was chosen only because it passed all the necessary internal tests (screen opening, call stack, return, sidebar). In general, the minimum required minimum.

In contrast to the widely loved by all, react-navigation , wix is declared 100% native. So it is - all transitions between screens are translated into java application code and work at the system level.
In the process of development, we encountered a terrible “white screen” bug that occurs only in some cases and on separate devices. It happens when you exit the "sleep" mode, the boot process just stops. Debagger and debug silent. On github on this issue, there were only strange hints of "... try to play" with the order of loading the screens and other sorcery. It is plainly not even clear at what level the problem is buried: the java-code of the android or already in the JavaScript machine. After we danced with a tambourine, the error began to appear less often, but did not go away at all, hanging on the list of unsolved problems. Alas.
With the exception of this "shoal" - everything is more or less tolerable and smooth. And, most importantly, native!
From the file system, we needed to store custom photos, as well as work with a couple of files associated with the backup. As a result of the choice of two possible options, the choice fell on react-native-fs

“Access to the native file system” - written at the entrance to the repository. Well, probably it is, but with some amendments and limitations.
1. Access is only asynchronous. As a result, sometimes you have to remember working with Promise / async / await. Although in React you start to forget about it.
Synchronous execution of an asynchronous function (await), requires that the current function be Asynchronous (async). To do this, simply add async before the function name. And yes, it works for the React.Component class method too. (In the React help, ReactNative is silent about this, although this is self-evident).
It is important to remember that after this function also becomes asynchronous! If she was already used somewhere before, recheck her call.
2. Full cross-platform access is only part of the file system. In fact, only to one directory: DocumentDirectoryPath. And this is, in fact, the directory in which the application resides. Forget about scanning the root directory, searching for images in the gallery, audio, etc. None of this is available.
But in general, solves its problems by 100%. In the piggy bank mast hev.
The task is both simple and complex. Simple, because everyone has an API - take it and use it. Difficult - I don’t want to crawl into the depths, and the time format did not allow me to sit and poke around in “possibly working” ways. We decided to find something that works 100% and is implemented in an already ready extension for React Native.
There was exactly one such: Google Drive. Work with the disk is understandable and is driven by trivial requests for API. But getting access to the application to the disk is another story.
React-native-google-signin is a system for managing authorization in Google services.

This is where we “had fun”. They wanted a simpler and more reliable, and got ...
It all started with getting the developer key. Previously, all this was done by Google itself. But after the absorption of FireBase, it was decided to transfer this function to its wonderful console.
So, to get the key, you need:
And then, yes. Something is starting to work. Rather, error codes in the responses of the service begin to be meaningful.
It is especially important to note that the API key obtained by the application directly when connecting to the service is not at all eternal. Sometimes it changes once a day, sometimes once a minute. Therefore, before contacting the service, it is always better to check first if the current key is expired. And if it is overdue, receive it again.
The process of obtaining the API key from Google is as follows:
So, for example, in our application, when opening the backup screen, we are trying to get the id of the backup folder from Google. If everything is successful, we get an id.
If not (error 401 arrived) - we are trying to get a new API key and repeat the request for getting the folder id with backup again.
Honor and praise of the moment.js The
acquaintance with this miracle began a long time ago and it was damn nice that it works just as well in React Native.
A bunch of formats, magical + - day / month / year. Support for multilingual and national formats. Beauty!
You can shower us with tomatoes, indicating that all this is easy to "rulitsya" hands with ordinary Date, but in the conditions of rapid development do not think about such things very, very useful!

React-native-charts-wrapper is a JavaScript wrapper for native android MPAndroidCharts.
I liked the presence of an abundance of different types of graphs (although at this stage we used only two of them - linear and “pie”).
Spoiled impression scant almost absent directory API. The author recommends to watch the documentation on the original MPAndroidCharts. In fact, the advice turned out to be difficult, since the development of the latter is carried out continuously and overtakes the implementation of the wrapper in several versions. In addition, MPAndroidCharts is written in Java. Wrapper - on javascript. Quickly figure out what's what is difficult, we have to think.

React-native-i18n -work like a charm, guys!
Although this component hangs on github with the mark Deprecated, it works without failures and jambs. All translations are neatly scattered over files with languages.
Using the parameters of the translator also works with a bang:
React Native has met almost all of its expectations. With it, you can relatively quickly assemble a prototype of the application, to work out the structure and usability. All the necessary tools for the "base" is.
On the other hand, there is always the risk of being in a “vacuum” when there are simply no ready-made solutions. So, for example, we did it when uploading a photo to the application - a component that can normally cut and pinch images is only one. And it did not start in our current build. If the need for it will be very “acute” - it will be necessary to update almost half of the system, which will certainly lead to another hunt for errors.
As our product, assembled on React Native on the market, will show itself over the coming months. But that's another story.
We talk about our own experience of working with the framework, ways of expanding the functionality, “pitfalls” (where can I go without them!) And how we got around them.
About the framework as a whole
A little bit about the hero of the occasion - React Native . He is still good!
For those who know enough JavaScript and especially NodeJS - it is very good. If there is experience with React, well, or at least there is an understanding of its idea, mechanism — it is simply great!
The main thing is that the output is a truly native application. Extensions and plugins cover almost 99% of typical tasks. The remaining percentage, if absolutely necessary, can be added in native languages (java, object-c) and connected to the React Native application.
But enough about the pros, there’s zero point to them, even though the list will be impressive. All the buns and goodies are meaningless if the application does not start, and this is the first thing that “pleased” us React Native.
At first, he didn’t like the NodeJS version. Then the npm version. Then the Android SDK version, then the Android tools version, then ... It makes no sense to write about how all the problems were solved, since from that moment all of the above software has updated its versions and instructions will be irrelevant.
Just know: React Native's bottleneck is the build environment. Get ready to google, read forums and stackoverflow. As a result, they spent on deployment: Ubuntu - 3 days, Win10 - 2 days. Strangely enough, everything turned out to be simpler on Windows, well, or just on ubuntu, there were “bumps” and already understood what to do.
Note that someone will come in handy: the code below solved all the problems with the compatibility of sdk versions of the add-ons when compiling the project.
subprojects {
afterEvaluate {project ->
if (project.hasProperty("android")) {
android {
compileSdkVersion 26
buildToolsVersion '26.0.3'
}
}
}
}
It is written in the /android/build.gradle file at the very end. Without this "directive", apparently, each of the plug-ins / extensions tried to compile on its own versions of the Android SDK, which resulted in building the project into a chaotic assortment of cruel mistakes and godless warnings. No one knows how relevant the recommendation will be in the future. But today, especially after Google forcibly forbade the use of the SDK below the 26th revision for compilation, this is very helpful.
The second “bottleneck” is pain not so much React Native, as, apparently, the whole of Open Source as a whole - limited support. The repositories are a bunch of unresolved issues. Fierce "smart" bots close bugs in the absence of activity, sometimes as many as 7 days later ... And everything seems to be fine. Nobody owes anything to anyone. Everyone is used to.

Patience burst when there was a "cant" with a banal text input in the usual TextInput. Just a text field. Just text input from the on-screen keyboard. After a couple of minutes of printing, the terrible lags and brakes of the system begin. They rushed to look for a problem - yes, there is one, it started with version RN 5x.xx Solve the problem? Not. Two or three issues on the topic just closed. A few more merged into one large .
I had to dig in, find out, try various options, change the RN version, in the hope that there was no such jamb there. As a result, by experiment, we managed to minimize dips in performance - we completely removed all the formatting and rewrote the input handler. But the unpleasant residue remained. The problem with the developers of the framework, by the way, has not been solved so far, six months have passed ...
Database
Realm is a smart database, with impressive functionality and running on Android, IOS, Windows.
At first there was a double feeling, they say, you’re not ORM, there’s really no sql, the record is kept only inside the callback. Unusually and strangely, especially for a web developer hailing from PHP, which grew up on ActiveRecord and Doctrine. But in fact, it turned out to be very easy and fast to jot down your minimum set of functions for CRUD. And all questions of taste and habits were resolved by reading the official reference, brief, concise and understandable.
And then the carousel of gifts started:
- Data encryption out of the box
- Lazy loading of data (pulls from the database only what you need right now)
- Real connections between entities (hello, mongo!
- Database structure versioning, with migrations out of the box
- And a bunch of small but pleasant things.

It seemed that the question from the database is closed completely. We work! The case went on until it reached the search. Or rather, before full-text search. Even more precisely, before full-text search in Russian, case insensitive. He did not work. Totally. He worked in English. Case sensitive also worked. But without a register, but in Russian - even cry. After digging the help, bugtracker and the Internet, it turned out that the developer, due to certain technical reasons, was very inconvenient to “think” about supporting multibyte encodings and everything that goes beyond the Latin alphabet. Well, he did not. Why not?
There is nothing to do, I had to find a workaround. As a result of a brief assault, a “volitional” decision was made - we make a separate field “fulltext_index”. In it we duplicate all the text in the upper register, simultaneously “cutting out” unnecessary punctuation, unnecessary problems and all sorts of garbage. After that, it is logical to assume that we are doing a search with a forced upper register.
Victory! Search now works like a clock, even in Russian, even in English!
Total: despite the problems with the register, the database works really fast, convenience is on the level, a lot of ready-made chips are out of the box - in general, I recommend.
Screen Navigation
wix / react-native-navigation is a simple and stable navigator (a router, as a web programmer would say).
It was chosen only because it passed all the necessary internal tests (screen opening, call stack, return, sidebar). In general, the minimum required minimum.

In contrast to the widely loved by all, react-navigation , wix is declared 100% native. So it is - all transitions between screens are translated into java application code and work at the system level.
In the process of development, we encountered a terrible “white screen” bug that occurs only in some cases and on separate devices. It happens when you exit the "sleep" mode, the boot process just stops. Debagger and debug silent. On github on this issue, there were only strange hints of "... try to play" with the order of loading the screens and other sorcery. It is plainly not even clear at what level the problem is buried: the java-code of the android or already in the JavaScript machine. After we danced with a tambourine, the error began to appear less often, but did not go away at all, hanging on the list of unsolved problems. Alas.
With the exception of this "shoal" - everything is more or less tolerable and smooth. And, most importantly, native!
File system
From the file system, we needed to store custom photos, as well as work with a couple of files associated with the backup. As a result of the choice of two possible options, the choice fell on react-native-fs

“Access to the native file system” - written at the entrance to the repository. Well, probably it is, but with some amendments and limitations.
1. Access is only asynchronous. As a result, sometimes you have to remember working with Promise / async / await. Although in React you start to forget about it.
Synchronous execution of an asynchronous function (await), requires that the current function be Asynchronous (async). To do this, simply add async before the function name. And yes, it works for the React.Component class method too. (In the React help, ReactNative is silent about this, although this is self-evident).
exportdefaultclassCloudIndexextendsBasePage{
async setupBackupFolders(init = false) {
// some stuff there...await RunSomeAsyncFuncInSyncMode(foo, bar)
RunFuncAfter(bar)
}
}
It is important to remember that after this function also becomes asynchronous! If she was already used somewhere before, recheck her call.
2. Full cross-platform access is only part of the file system. In fact, only to one directory: DocumentDirectoryPath. And this is, in fact, the directory in which the application resides. Forget about scanning the root directory, searching for images in the gallery, audio, etc. None of this is available.
But in general, solves its problems by 100%. In the piggy bank mast hev.
Cloud access
The task is both simple and complex. Simple, because everyone has an API - take it and use it. Difficult - I don’t want to crawl into the depths, and the time format did not allow me to sit and poke around in “possibly working” ways. We decided to find something that works 100% and is implemented in an already ready extension for React Native.
There was exactly one such: Google Drive. Work with the disk is understandable and is driven by trivial requests for API. But getting access to the application to the disk is another story.
React-native-google-signin is a system for managing authorization in Google services.

This is where we “had fun”. They wanted a simpler and more reliable, and got ...
It all started with getting the developer key. Previously, all this was done by Google itself. But after the absorption of FireBase, it was decided to transfer this function to its wonderful console.
So, to get the key, you need:
- Register the application on the google developer console to "enable" access to the Drive service.
- Register the application on the firebase console.
- Generate a google-services.json file in the firebase console - in which the service keys are wired.
- Slip this file into a project with the react-native-google-signin extension installed.
And then, yes. Something is starting to work. Rather, error codes in the responses of the service begin to be meaningful.
It is especially important to note that the API key obtained by the application directly when connecting to the service is not at all eternal. Sometimes it changes once a day, sometimes once a minute. Therefore, before contacting the service, it is always better to check first if the current key is expired. And if it is overdue, receive it again.
The process of obtaining the API key from Google is as follows:
await GoogleSignin.hasPlayServices()
const userInfo = await GoogleSignin.signIn()
this.setState({
userInfo: userInfo,
})
settings.set('google.drive.key', userInfo.accessToken)
trace('>> Key obtained:', userInfo.accessToken)
this.apiKey = userInfo.accessToken
So, for example, in our application, when opening the backup screen, we are trying to get the id of the backup folder from Google. If everything is successful, we get an id.
backupRootID = await Storage.safeCreateFolder({
name: backupFolder,
parents: ["root"],
}).catch((e)=>{
if(e.status == 401) {
trace(' >> Google signin unauthorized', e)
signGoogle()
returnfalse
} else {
trace(' >> Google signin failed', e)
}
})
// Yeahh. The api key is valid, and rootID found on GoogleDrive!
SomeStorage.setRootId(backupRootID)
If not (error 401 arrived) - we are trying to get a new API key and repeat the request for getting the folder id with backup again.
And a few more pleasant things.
Work with dates and time
Honor and praise of the moment.js The
acquaintance with this miracle began a long time ago and it was damn nice that it works just as well in React Native.
A bunch of formats, magical + - day / month / year. Support for multilingual and national formats. Beauty!
You can shower us with tomatoes, indicating that all this is easy to "rulitsya" hands with ordinary Date, but in the conditions of rapid development do not think about such things very, very useful!
Graphs and Charts

React-native-charts-wrapper is a JavaScript wrapper for native android MPAndroidCharts.
I liked the presence of an abundance of different types of graphs (although at this stage we used only two of them - linear and “pie”).
Spoiled impression scant almost absent directory API. The author recommends to watch the documentation on the original MPAndroidCharts. In fact, the advice turned out to be difficult, since the development of the latter is carried out continuously and overtakes the implementation of the wrapper in several versions. In addition, MPAndroidCharts is written in Java. Wrapper - on javascript. Quickly figure out what's what is difficult, we have to think.
Multilingual and translations

React-native-i18n -work like a charm, guys!
Although this component hangs on github with the mark Deprecated, it works without failures and jambs. All translations are neatly scattered over files with languages.
Using the parameters of the translator also works with a bang:
// en.js
sync: {
success: 'All items are up to date!',
progress: 'Sync Notes %{idx} of %{total}'
}
//app.jsimport I18n from'react-native-i18n'import en from'./en.js'
I18n.translations = { en }
I18n.locale = "en"const _t = (msg, data) => { return I18n.t(msg, data) }
console.log(_t('sync.progress', {idx: 3, total: 10}))
The bottom line
React Native has met almost all of its expectations. With it, you can relatively quickly assemble a prototype of the application, to work out the structure and usability. All the necessary tools for the "base" is.
On the other hand, there is always the risk of being in a “vacuum” when there are simply no ready-made solutions. So, for example, we did it when uploading a photo to the application - a component that can normally cut and pinch images is only one. And it did not start in our current build. If the need for it will be very “acute” - it will be necessary to update almost half of the system, which will certainly lead to another hunt for errors.
As our product, assembled on React Native on the market, will show itself over the coming months. But that's another story.