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
- Navigation — Setup & Pitfalls — React Navigation
- UI / UX — Reducing BoilerPlate Code using Toolkit
- 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
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.
Feature 1: Camera Modal Setup
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…
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.
Overriding tabBarOnPress on BottomTabNavigator
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
You can detailed instructions for this functionality here :
Feature 2 : Search Header Across HomeTab
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
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
SearchBar Screen Modal Transition with Shared Header across screens
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.
- 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.
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.