Building my first Mobile App - Part 1: Setting up using React Native and Expo

8 min read

So, for my next project, I’ve decided to build a mobile app.

The (tentative) name of the app is Keep UP. It is a Personal Relationship Management tool to helps you keep up with friends & family.

Here’s how it is meant to work:

  • The user adds a contact. Mostly just the name.
  • The user can add a note about the contact.
  • The user can then add reminders for the contact. That is: an event with a start date and then optionally an end date. Can also set this to be recurring.

This article series will cover the process I went through to build the application.

In Part 1, I will show how I set up a new React Native project using Expo, add multiple screens and add a bottom bar navigation to switch screens.

What stack to use

Currently, there’s several ways to build mobile apps. There’s pure native development using Java or Kotlin for Android and Objective-C or Swift for iOS. There’s also several hybrid tools such as React Native, Ionic and Flutter.

After some consideration, I decided to go with React Native because:

  • It helps that I have some web development experience with React
  • There is no need to learn Java/Kotlin on Objective-C/Swift and all the other things that go with mobile app development.
  • I decided not to use Flutter because I don’t want to have to learn Dart too.
  • I can get a more native feel/performance as opposed to Ionic.

In order to move faster, I decided to use Expo to build the application.

Installing Expo

To install Expo, I followed the instructions on the website, but faced a few issues

  • I had to install typescript
  • I had some permission issues when trying to install both Typescript and Expo globally. Ended up using sudo (muahahahaha).

Initializing the project

To initialize a project with expo, we have to run the command: expo init my-project

Doing this, I was faced with a decision:

expo initexpo init

Decided to go with blank because:

  1. I don’t know how to use Typescript. I’m already learning React Native on this project, no need to pile on more stuff.
  2. Since it’s my first time, I’ll prefer a managed workflow to get me going faster.
  3. From the mockups I have for the app, I won’t be using tabs.

After all had been initialized, I was left with a pretty nice directory structure, and an App.js file at the root of the project with this:

// App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Running the program

Testing out the program was pretty dope using Expo.

All I had to to was cd into the directory and run npm start.

I got a really nice dev tools page, and I could view the program from my Android phone by downloading the Expo app and scanning the QR code.

Adding Navigation

The next thing I felt I needed to figure out was Navigation.

To add navigation, I did some googling and found the react-navigation library. To install, I ran expo install react-native-gesture-handler react-native-reanimated.

Following the direction in the documentation here, I added the navigation to the default code in App.js to leave me with this:

// App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';

class HomeScreen extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Open up App.js to start working on your app!</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
});

const AppContainer = createAppContainer(AppNavigator);

export default class App extends React.Component {
  render() {
    return <AppContainer />;
  }
}

Adding React Native Paper

I’m a fan of Material Design and want to follow it (as much as I can) for this application.

Thankfully, since Material design is so popular, there is a great package to help with getting it right.

From my research, the most popular (by far) is React Native Paper.

To add it to the project, I ran expo install react-native-paper and then reading further down the Getting Started documentation, I also installed babel-plugin-optional-require to reduce my bundle size when building for production using npm install --save-dev babel-plugin-optional-require.

After that, I modified babel.config.js (found at the root of the project) to look like this:

// babel.config.js
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    env: {
      production: {
        plugins: ['react-native-paper/babel'],
      },
    },
  };
};

Now, in App.js, we’ll import react-native-paper and add it to the render:

// App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { Provider as PaperProvider } from 'react-native-paper';

// Other code follows as usual...

export default class App extends React.Component {
  render() {
    return (
      <PaperProvider>
        <AppContainer />
      </PaperProvider>
    );
  }
}

Reorganizing the components

At this point, I feel like we should structure the code better, so we’ll move the home component into a different file and import:

Let’s create a folder called views and a file name home.js inside it.

Then we’ll put this in ./views/home.js:

// ./views/home.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    },
});

export class HomeScreen extends React.Component {
    render() {
        return (
            <View style={styles.container}>
                <Text>Open up App.js to start working on your app!</Text>
            </View>
        );
    }
}

Then we refactor App.js to this:

import React from 'react';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { Provider as PaperProvider } from 'react-native-paper';
import { HomeScreen } from './views/home';

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
});

const AppContainer = createAppContainer(AppNavigator);

export default class App extends React.Component {
  render() {
    return (
      <PaperProvider>
        <AppContainer />
      </PaperProvider>
    );
  }
}

Adding more screens

Now, I want to add another screen to show a list of saved contacts.

I’ll create a new file ./views/contacts.js and mostly duplicate the content from ./views/home.js:

// ./views/contacts.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    },
});

export class ContactsScreen extends React.Component {
    render() {
        return (
            <View style={styles.container}>
                <Text>Open up ./views/contacts.js to edit this screen!</Text>
            </View>
        );
    }
}

Then we update our App.js to look like this:

// App.js
import React from 'react';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { Provider as PaperProvider } from 'react-native-paper';
import { HomeScreen } from './views/home';
import { ContactsScreen } from './views/contacts';

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Contacts: {
    screen: ContactsScreen,
  },
});

const AppContainer = createAppContainer(AppNavigator);

export default class App extends React.Component {
  render() {
    return (
      <PaperProvider>
        <AppContainer />
      </PaperProvider>
    );
  }
}

Adding a bottom bar

While we have two screens, we currently have no way of switching between them

Earlier, I mentioned that I did not want to use tabs for navigation. Well, my chosen navigation element is a bottom bar.

Thankfully, there is good documentation on creating a material bottom bar navigation for react-navigation. Also, it uses react-native-paper so.. YAY!.

To do this, I first had to install the appropriate library: npm install --save react-navigation-material-bottom-tabs.

Then, I updated App.js to this:

import React from 'react';
import { createAppContainer } from 'react-navigation';
import { Provider as PaperProvider } from 'react-native-paper';
import { HomeScreen } from './views/home';
import { ContactsScreen } from './views/contacts';
import Icon from 'react-native-vector-icons/FontAwesome';
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';

const AppNavigator = createMaterialBottomTabNavigator(
  {
    Home: {
      screen: HomeScreen,
      navigationOptions: {
        tabBarIcon: ({ tintColor }) => (
          <Icon name="home" size={20} color={tintColor} />
        )
      }
    },
    Contacts: {
      screen: ContactsScreen,
      navigationOptions: {
        tabBarIcon: ({ tintColor }) => (
          <Icon name="users" size={20} color={tintColor} />
        )
      }
    },
  },
  {
    initialRouteName: 'Home',
    activeColor: '#000000',
    inactiveColor: 'rgba(0, 0, 0, 0.54);',
    barStyle: { backgroundColor: '#FFEB3B' },
  }
);

const AppContainer = createAppContainer(AppNavigator);

export default class App extends React.Component {
  render() {
    return (
      <PaperProvider>
        <AppContainer />
      </PaperProvider>
    );
  }
}

Conclusion

So, I’ve created the “skeleton” for the application, next I’ll have to figure out a storage system and then begin to flesh out the screens.

If you have any thoughts or suggestions, let me know in the comments. Till next time ✌🏾.

Powered By Swish

Comments