react native from a front-end developer's perspective

A first look at React Native from a front-end developer's perspective

If you are a front-end developer that has been working with React Redux, you might want to take a look at React Native. It enables the development of cross-platform iOS and Android applications with React components utilizing the fundamental UI building blocks of each platform. One advantage of React Native is the constant framework development and improvements in each release designed to facilitate the overall development process.

A year ago, I decided to try this technology and create a React Native app. I started with a simple dictionary application that allows you to group words while saving them in certain categories.

react-app

At that time, I used React Native V0.37.0 version. A few weeks ago, I thought it would be a good idea to continue the development. To proceed, I needed to use V0.53.0. This was the moment I was faced with the standard problem of fast-growing projects: fundamental functionality changes. To launch the app, I had to do some refactoring. At first, I didn’t like these changes but later realized they actually increase development speed and quality.

Now, I’d like to tell you about some peculiarities I’ve come across while developing a React Native app.

Currently, there are two approaches when it comes to creation of an app: utilizing the create-react-native-app or react-native init. Create-react-native-app is an npm package that allows you to create an initial app structure from scratch and launch it on a smartphone without installing the environment for each platform (iOS and Android). However, if you need to enhance the app with native code or add a library, you will still need to install the environment.

Note that there is neither CSS or HTML, but only jsx syntax and syntax for styling. This is very similar to inline styles in HTML. React Native utilizes the flexbox principle the same as in the WEB. React Native does not have HTML elements, but there are React Native components. There are also cross-platform components (View, Button, TextInput) and platform-dependent (DatePickerIOS, ProgressBarAndroid, & other).

Here is the development of a component for a card displaying the category of words.

react app development

This is how a jsx markup for this component looks like:

<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>

The view component is similar to div (the one that is used in Web) and remains one of the most important while creating components. TouchableNativeFeedback is a component that processes a click on the embedded element. ColoredFlatButton and Icon are components from the react-native-material-kit library. As we see from the above example, component building in React Native is similar to component building in React with the following difference: instead of HTML, the React Native elements are used.

Now let’s take a 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',
   },
});

To create styles, you need to import the StyleSheet class from React Native and add styles object to it.

  <View style={styles.cardActions}>

There is probably no need to describe the styles syntax in detail since for any person familiar with CSS it’s pretty clear. The only difference is that the dimensions are specified not in CSS units, but in density-independent pixels, thus making your app look the same on different sizes and resolutions of iOS and Android devices.

Once you have more than one page in your app, it’s time to think about how to shift between them. Until recently, adding app navigation was quite challenging.

Here is an example of how it used to be done.

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}
           />
       );
   }
}

You’ll agree that this doesn’t look well. With native-navigation, react-native-navigation, and react-navigation packages recommended in the official documentation, the situation has completely changed. For my app, I used the React Navigation package. It turned out to be quite simple. You just need to import the navigator and specify the settings.

const RootNavigator = DrawerNavigator(
   {
       [RoutesID.CATEGORY]: {
           screen: CategoryScreen,
           navigationOptions: {
               drawerLabel: 'Category',
               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 where you specify settings for the header of each page. The second parameter is the setting for the Drawer component. Drawer component is a left side menu, which is opened after clicking a burger icon. The integration with Redux is also possible.

After adding navigation and several screens, it’s time to think about how to save the data. If the app does not utilize an internet connection, the data can be stored on the device. SQLite can help with this. To work with the database, I used the react-native-sqlite-storage package. To be honest, I have some trouble during installation. However, later the problem was obvious: after installing this package, it was necessary to reinstall the app on my device. I used the approach in which a database is pre-filled and saved on the project. In this case, the database is automatically added during the process of app installation (more details on how to utilize this approach here).

In this case, to install the connection requires only one code line.

open() {
       return SQLite.openDatabase({ name: 'englishAppDB.db', createFromLocation: 1 }).then(
           (db) => {
               this.db = db;
               Promise.resolve();
           },
           error => Promise.reject(error),
       );
}

Here is also 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),
   );
}

For now, the app features include: add a word/category to the dictionary, select the words you’d like to learn and test your knowledge, and customization of category color. Some new features I would like to add are other exercises for studying words, the ability to import/export words, and color themes for the application.

react custom development

All in all, when it comes to React Native, I’m more than pleasantly surprised with the available features and how easy it is to use. Since most of the apps provide a simple feature set, with React Native you can use web development knowledge to create apps. A nice addition here is that there is a convenient debugging mechanism in the browser similar to the debugging mechanism of web applications.

And the cherry on top? If by any chance there is some functionality you need, the React Native community is always available and willing to help.


Created by Artem Kushal