For the Ionic Framework tutorial, check out part 1 of this series.
Part 2: React Native
React Native is an open-source cross-platform development library that makes it extremely easy for React.js developers to build native apps for Android and iOS. It supports JSX for creating UI components, and has a handful pre-defined components that you can (and should) use in building your app’s custom components. Those pre-defined components are the only components that are translated into native view elements in the corresponding mobile device platform. Additionally, there are a number of UI libraries you can use on top of React Native to make your development much much easier and simpler; for example, NativeBase and UI Kitten.
Unlike Ionic, React Native renders truly native view elements within the app. The cool thing is that the business logic is written in Javascript/Typescript and runs on Android or iOS. This eliminates the need to learn and develop in different programming languages, like Java or Swift, to build apps for different operating systems.
You will find the complete code of this tutorial in this repository:
Now let’s get started with our project.
Prerequisites
Setup
Open the terminal and navigate into a directory of your choice, then run the following command to create a new blank React Native project:
expo init whatsapp-clone
When prompted, choose the blank (TypeScript) template for this project. After the process completes, the project should be created and ready. Navigate into the newly created directory using the following command:
cd whatsapp-clone
To make things simpler, we will use a couple of tools to help us with the UI; in particular, NativeBase and Moment.js. So let’s start installing those dependencies.
Firstly, install NativeBase:
yarn add native-base --save
Next, you will need to run this command to install the fonts package:
expo install expo-font
Finally, install Moment.js:
npm install moment --save
Now, you can start the dev server to launch the app:
yarn start
The DevTools should open up on your browser automatically. Start the Android emulator and click “a” on your keyboard to run the app on the emulator, or scan the QR code to run it on your mobile device (Expo app is required).
UI Implementation
Open up the project with your favorite IDE. As you can see in the screenshot below, in the main screen of WhatsApp, there is a header with a couple of buttons and four tabs.
The tab content (displayed under each tab) is rendered only if the corresponding tab is selected. To make our implementation much simpler, let’s get some help from NativeBase components. The Header
component can be used of course for the header, including the buttons, and the Tabs
component for the tabs and their content. Create the following directory: whatsapp-clone/src/components and create two files inside of it: MyHeader.tsx and MyTabs.tsx. Those two files will be the main components of our app. Now, let’s set up NativeBase in our app and render those components from our main screen. Open up App.tsx and replace its content with the following:
Most of what is happening here is bootstrapping our app and importing NativeBase fonts and icons. The important part is the return
statement of render()
. Within a Container
, we are rendering our previously created components. Right now the screen will display nothing as those components are empty.
Let’s set up our theme colors so that they are ready when we need to use them in our components. Create src/constants/ThemeColors.ts, and add the following:
This is a very simple way to have your app’s theme colors available from a single source. We can import this object in any component in our project and use the colors without going through the hassle of having to write the hex color values on each style property where it is needed. Now head over to components/MyHeader.tsx and copy and paste the following in its content:
Basically, we are importing here the necessary components from NativeBase and our theme colors. Then, we are rendering a Header
with a couple of Icon
-only Button
s on the right-hand side. NativeBase Header
has a few useful properties, noShadow
, hasTabs
and transparent
, which we use here to make the header look more like WhatsApp’s, and we set the background color of the header to our primary
color from ThemeColors
.
Open src/components/MyTabs.tsx and write in it the following:
So far, we do not have any mock data to display, but that will be taken care of later. Let us have a look at what is happening in MyTabs.tsx. Setting the initialPage
property on Tabs
to “1” will ensure that “Chats” will be the selected Tab
when the app loads. For each Tab
, we set the appropriate styles to make them similar to WhatsApp’s.
Custom components
We will have to render each tab’s content within the corresponding Tab
component. Therefore, let us create the following three files inside src/components: Chats.tsx, Status.tsx and Calls.tsx.
Open up Chats.tsx and add to it the following:
Using the List
, and ListItem
components, we will render the contacts and their chat snippets under the “Chats” tab. We can suppose that we will receive the data to display as an Array, chats
, through the components props
. With that, we pass this.props.chats
to dataArray
property of List
and use keyExtractor
to assign a unique key to each element which will be rendered within this List
.
renderRow
will dictate how each item in the List
will look like. And of course, here is where Moment.js can come in handy. We suppose chat.time
to be of type Date
. So we pass it to Moment()
and chain format()
to the returned object in order to format the date into a short string that displays the time. We also set a FAB
button to the bottom-right of the screen.
Head over to Status.tsx, and write in it the following:
In this component, we pretty much render the same list, but with some modifications and a couple of ListItem
s above it. The first ListItem
displays the status of the current user, and so we use the URI of the user’s avatar from the component’s props
. The second ListItem
serves a divider between the first ListItem
and the List
. I wrote getFormatedDate()
function to return a string, from the Date
parameter, in the required format, and display that in each ListItem
. This should do it for this component!
Finally, open up components/Calls.tsx and copy and paste in it the following:
The implementation here is pretty straightforward. The only noticeable difference here is the Button
set on the right-hand side of each ListItem
. With that, our custom components are ready and each can be used as content for a tab.
Adding Mock Data
Return to components/MyTabs.tsx and let’s modify it to render the custom components under the corresponding tabs and pass some mock data to fill up those components. MyTabs.tsx should now look like this:
I defined three interfaces in order to understand what kind of data objects we are passing to the components as props
. Technically, we could have used only a single interface and array for all the components props
, since the information to be displayed in the components is, more or less, alike. However, this should give you a better idea how the data objects in a real-world application would be structured. Often you will have data objects of different structures (interfaces) and each, possibly, passed to a different component.
state
is assigned to all the data objects we will need in our components. Practically, you would probably retrieve these data from a server by calling a REST API, and later assign them to the component’s state. For simplicity, we will retrieve them from getChats()
, getStatusItems()
, and getCalls()
. Within the tags of each Tab
component, we render the component that corresponds to the content of that tab
. We also pass the data stored in state
as props
, for example: <Status statusItems={this.state.statusItems} user={this.state.user} />
.
Now, save your project and check out the running emulator.
And that is it!
Up to this point, we should have a decent clone of WhatsApp’s main page. Congrats! You should now have a good idea on how easy it is to build apps using React Native.
Again, here you will find the complete code of this tutorial.
Follow the steps in README to set it up. If you have any questions or comments, drop them below.
Don’t forget to CLAP, if you liked this tutorial.
See you in part 3 for the comparison!