Building my first Mobile App - Part 1: Setting up using React Native and Expo
- Part 1: Setting up using React Native and Expo
- Part 2: Ditching Expo
- Part 3: Adding authentication with firebase
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 init
Decided to go with blank
because:
- I don’t know how to use Typescript. I’m already learning React Native on this project, no need to pile on more stuff.
- Since it’s my first time, I’ll prefer a managed workflow to get me going faster.
- 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 ✌🏾.