Building Facebook Messenger Clone in React Native.

July 12, 2018 0 Comments

Building Facebook Messenger Clone in React Native.

 

 

Customised Image src: https://blog.discordapp.com/

Airbnb published a lengthy, five-part blog post announcing and explaining their decision sunsetting React Native and reinvesting all of the efforts back into native. Just like everyone, When someone asks me “Should we use React Native?” I could say ‘yes’ confidently pointing out companies like Airbnb, Tesla … etc. Sadly, Airbnb has left the nest along with Udacity Mobile Team.

But that doesn’t mean its going down, React Native is progressing faster than ever. There have been over 2500 commits in the last year and Facebook just announced that they are addressing some of the technical challenges we faced head-on.

Still I would like to say we encountered most of the problems airbnb pointed out, But its safe to say RN is in that sweet spot right now. Microsoft is using it for the new version of Office and completely re-writing the new Skype app in react native. Also Visual Studio Code — Best Editor for React right now is from Microsoft.

So with everyone making decisions, I thought about building a scalable application in react-native to make sure things are cool. Since I am working on a chat module using firebase, Facebook messenger popped into my mind. Can I build something like Messenger only using react-native ?? Turns out I could do most of the things in react-native … Not everything but close.

This article explains different steps I used and issues encountered while building the app. We will start with navigation and then jump to UI and finally hook functionality with the help of firebase , making things truly functional.

So the entire process is divided into 3 main parts

  1. Navigation — Setup & Pitfalls — React Navigation
  2. UI / UX — Reducing BoilerPlate Code using Toolkit
  3. Functionality/ Firebase Integration — (Possibly next post ;) )

So the best option for navigation in react native is react-navigation. It has support for different types of navigation we will be using in the app. The setup procedure is smooth. We can easily define the navigation stack just by looking at the existing app.

In the root there will be StackNavigator followed by the bottom navigation in the main screen. The first screen ‘Home’ will be a TopTabNavigator and the other will screens/stacks as needed. So the basic navigation tree will be as follows

index page -navigation
Bottom Navigation and Top Tab Navigation
Final Result — Everything inside a single navigation stack

We now have a working navigation system similar to the existing app. But there are some add-ons needed other than the normal navigation. That would be

  • Open CameraScreen as a modal when clicking on Camera Button in Bottom Navigation.
  • Search Header on the top shared between all screens in Home Tab Navigation.

Our primary objective should be to solve these issues in the simplest way possible without much code refactor & issues.

A modal displays content that temporarily blocks interactions with the main view

For opening screen as a modal (bottom to top animation) we can use mode property in navigation. But if we add mode:'modal' to the root navigator, It will affect all the screens that we are going to define in the future. We only need to make this working for CameraScreen. So Instead separate the screens from the root navigator…

Modal setup that affects only camera screen

Phew .. The first half is done…

Now the next challenge, we need to open CameraScreen when user presses the camera button which is in fact a TAB in BottomTabNavigation.

We will need to override the onPress to navigate to modal Camera Screen. For that the navigationOptions has tabBarOnPress property that we can override to make this possible.

And the result

Camera Modal Screen

You can detailed instructions for this functionality here :

Thanks to Spencer Carli : https://egghead.io/lessons/react-native-open-a-modal-from-tab-bar-in-react-navigation

For messenger we have an option to search across the app. This bar is shared by all four tabs in home section. Now most of us do this the first wrong way that comes into mind (At least I did this for 2 apps).

  • Define a main Screen
  • Add the main bottom navigation inside the screen
  • Add the UI for search-bar above the navigator

This is a Big Mistake Why??!

Explicitly rendering more than one navigator
Most apps should only ever render one navigator inside of a React component, and this is usually somewhere near the root component of your app. This is a little bit counter-intuitive at first but it’s important for the architecture of React Navigation.

Meaning if we define our bottom navigation inside a screen, It will have its own navigation state, props and be unable to interact with parent navigator.

We can manually hook up our child navigator using screenProps or using redux integration to both navigators, But all of this sounds like a lot of work to do for just defining header for the navigation.

Refer React-Navigation-Common-Mistakes for more details why you should avoid this approach

So what’s the best way to achieve this search header functionality?

Just use the header prop in your MainScreen inside ModalStack. Also give header:null for ModalStack to avoid multiple headers. Also make sure headerMode:'none' is not specified for ModalStack as these will remove headers specified in the options

Functional Search Bar

We got the search option working now. But now you must be thinking how will this component interact with all other screens. I had the same confusion. The messenger opens a new screen when the search field is focused. I think we can use redux eventually to communicate with other parts of the app & for the other transition part

When we click on the Search option at the top in Messenger, mainly two things happen

  • Search Input field gets focused
  • We are routed to a new search screen using a modal transition.

How can we do this using react-navigation?? Our current header implementation & Stack Configuration has multiple flaws now.

Main Problem

  • Header is now unique to MainScreen only, meaning even if we add a new header for SearchScreen it will be different. So user will see multiple headers (ie. same header component showing in different screens now)

Solution 1: Move the Header to our main Stack Configuration

Since our Modal Stack has screens including BottomNavigator, CameraScreen & SearchScreen , the header gets shared for all screens. So camera screen will also show this header. We don’t want that…

So the best way is to create a Search StackNavigator that has bottom navigation & SearchScreen defined in it and a global header.

SearchHeader shared between Bottom Navigator & SearchScreen

No we have shared functional header for both screens. Let’s add additional setup for handling focus events and handling back press events.

With a fully fledged working navigation, I think we are safe now to start with UI/UX in the app.

In my last post ‘ Super Cool Material UI components in React Native!’ In my last post I described why it’s better to use small libraries instead of a using fully packed UI toolkits. But it’s not the case…

  • App follows strict platform guidelines.
  • No need to write custom code for all those ripple effects and everything
  • Toolkits will have a broad range of components (Android & iOS)
  • Able to use components like Toolbar, Card, Drawer etc from a single lib.

So we will need one of the best toolkits available in react native to mock the native feel & experience. So I did a lot of research where I was able to find toolkits like NativeBase, material kit, material-ui and of course react-native-paper. Finally I decided to use Paper .. why ??

Provides a consistent and smooth user experience with Platform Adaptation.

Paper: Platform Adaptation

We will able to use components like TouchableRipple that works superb on Android and iOS following guidelines. Paper also support dynamic theming support for the app (Feature Enhancement : Dark Mode ;) )

Another great thing about using a toolkit like Paper is reducing the boilerplate code we need to write.

The best example for this would be the Toolbar & Search bar. I had to write about 120 lines of code to achieve this functionality. But with Paper , The number of lines reduced to less than 40 , exponentially increasing the code readability.

Thanks to all the contributors including Satyajit Sahoo for this awesome toolkit…

I used https://randomuser.me/ api for generating random user data. They also have some nice user images support as well, that worked for me great.

CameraScreen implemented with the help of react-native-camera . This lib has support for facial recognition as well. With the help of an overlay system and a simple API behind we could do some interesting things. But I don’t think this is going to work as great as the native app. Native does has its perks when it comes things like camera & high performance media rendering.

I will be including the functionality as soon as possible. Will be using react native firebase to integrate one to one chat and group chat as a module.

Next part of this post will cover the firebase integration with offline support along with the chat interface UI with more on the UI & Paper features.

TL;DR : Source Code — React-Native-Messenger (WIP)

Sample APK Download (Updated : v1.1) here

Comments or questions? Ask me on Medium , Github or Twitter.


Tag cloud