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 ✌🏾.