If you are a frontend developer, and also with the experience of react + redux, then you should definitely pay attention to such an interesting tool as react-native. It allows you to develop cross-platform applications for ios and android. React-native is under active development and releases updates every month.
A year ago, I had a desire to try this technology and I began to write a dictionary application that allows you to save a category of English words with their translation. The react-native version at that time was 0.37, now version 0.52. A few weeks ago, I decided to resume development and faced the standard problem of fast-growing projects, namely, a fairly frequent and cardinal change of functionality. I had to rewrite some things in order for the application to start. At first I didn’t like it much, but then I realized that these changes increase the speed and quality of application development. Then I would like to briefly review the main points of development on react-native, which I encountered in the process.
At the moment you can create an application in two ways: using
create-react-native-app and react-native init. The create-react-native-app is an npm package that allows you to create the initial structure of the application and run it on a smartphone without setting the environment for each of the platforms. However, if you need to add native code to the application or connect the library that does this, then you still need to set up the environment.
And now you already have a finished project, but what to do next? After all, we have neither CSS nor HTML. But we have jsx syntax, as well as syntax for styling, very similar to inline styles in html. For the layout of the layout used flexbox is the same as on the web. In react-native, there are no HTML elements familiar to the front-end developer of the developer; instead, there are react-native components for the layout, which can be found on the
official website . There are cross-platform components (View, Button, TextInput), as well as platform-specific components (DatePickerIOS, ProgressBarAndroid, etc.). Let's look at the development of a component using the example of creating a card to display a category of words.
')
Below is the jsx markup for this component.
<View style={[styles.card, customStyle]} elevation={5}> <TouchableNativeFeedback onPress={() => onCardBodyClick(categoryId, categoryName)} background={TouchableNativeFeedback.Ripple('black')} > <View style={styles.cardBody}> <Text style={styles.bodyText}>{categoryName}</Text> </View> </TouchableNativeFeedback> <View style={styles.cardActions}> <ColoredFlatButton onPress={() => onRemove(categoryId)}> <Icon size={18} name="close" color="grey" /> </ColoredFlatButton> <ColoredFlatButton onPress={() => onEdit(categoryId)}> <Icon size={18} name="mode-edit" color="grey" /> </ColoredFlatButton> <ColoredFlatButton onPress={() => onStudy(categoryId)}> <Icon size={18} name="school" color="grey" /> </ColoredFlatButton> </View> </View>
View component is similar to a div in the web and is one of the main components when creating a component. TouchableNativeFeedback is a component that allows you to handle clicking on an element nested in it. The ColoredFlatButton and Icon components from the react-native-material-kit library. As you can see from the example above, the layout in react-native is no different from the layout in react, except that components from react-native are used instead of HTML elements.
Next we look at the styling of this component.
const styles = StyleSheet.create({ card: { marginTop: 10, width: 160, height: 140, justifyContent: 'flex-end', }, cardBody: { flex: 1, padding: 16, justifyContent: 'flex-end', }, bodyText: { fontSize: 18, color: 'white', }, cardActions: { padding: 8, flexDirection: 'row', backgroundColor: 'white', justifyContent: 'space-between', alignItems: 'flex-end', }, });
In order to create styles, you need to import the StyleSheet class from react-native and pass it the style object. To apply a style to an element, you need to specify it in the style attribute.
<View style={styles.cardActions}>
I think that we will not understand the styles, a person familiar with css and so everything is clear. The only difference is that dimensions are not specified in CSS units of measurement, but in Density-independent Pixels. These are units of measurement that allow an application to look the same on different screens and resolutions in IOS and Android.
After more than one page appears in the application, it is worth considering how to make the transition between them. Until recently, adding navigation to the application was quite difficult.
I will give an example of how this was done before.
const _navigator = null; class EnglishApp extends Component { onNavBackPress = () => { _navigator.pop(); }; renderScene = (route, navigator) => { _navigator = navigator; switch (route.id) { case routeIDs.NEW_WORD: return <SingleWordScreen navigator={navigator} onNavIconClicked={this.onNavBackPress} />; case routeIDs.WORD_LIST: return <WordListScreen navigator={navigator} onNavIconClicked={this.onNavBackPress} />; } }; render() { return ( <Navigator initialRoute={routeIDs.CATEGORY} renderScene={this.renderScene} configureScene={(route, routeStack) => Navigator.SceneConfigs.FloatFromRight} /> ); } }
Agree, does not look very? Now the situation has changed, several packages have appeared that are recommended in the documentation (
native-navigation ,
react-native-navigation ,
react-navigation ). I used react-navigation. Everything turned out to be simple, just import the navigator and specify the settings.
const RootNavigator = DrawerNavigator( { [RoutesID.CATEGORY]: { screen: CategoryScreen, navigationOptions: { drawerLabel: '', drawerIcon: ({ tintColor }) => ( <Icon name="local-library" color={tintColor} size={22} /> ), }, }, [RoutesID.NEW_WORD]: { screen: NewWordScreen, navigationOptions: { drawerLabel: () => null, }, }, }, { drawerWidth: 250, drawerPosition: 'left', contentOptions: { inactiveTintColor: 'darkgray', }, drawerOpenRoute: 'DrawerOpen', drawerCloseRoute: 'DrawerClose', drawerToggleRoute: 'DrawerToggle', }, );
The first parameter is the application routes, and you can also specify the settings for the header of each page. The second parameter is the settings for the component Drawer - this is the menu that opens to the left by clicking on the burger icon. There is the possibility of integration with redux.
After navigation and several screens appeared in the application, you should think about saving data. If the application does not use an Internet connection, then you need to store data on the device. For this we have SQLite. To work with the database I used the package
react-native-sqlite-storage . I tinker a bit with the installation, and the problem turned out to be obvious, after adding this library to the project, it was necessary to reinstall the application on the device. I used the method in which the project already has a database that is used when installing the application on the device, as described on the module page in github. To establish a connection, you need only one line.
open() { return SQLite.openDatabase({ name: 'englishAppDB.db', createFromLocation: 1 }).then( (db) => { this.db = db; Promise.resolve(); }, error => Promise.reject(error), ); }
As well as a simple example of a database query.
getAllCategories() { return this.db.executeSql('SELECT * FROM category', []).then( ([{ rows }]) => { let category = new List(); for (let i = 0; i < rows.length; i += 1) { category = category.push(new CategoryRecord({ id: rows.item(i).Id, name: rows.item(i).name, color: rows.item(i).color, })); } return category; }, error => Promise.reject(error), ); }
In conclusion, I can say that after using react-native I was pleased with this technology. Convenient debugging in the browser, no difference from debugging web applications. If there is no functionality, you can always find a library in the community of react-native specialists.
Repository link