This is a guest post by the React Native Paper team. If you like this guide, check out React Native Paper for more!
In this blog post, we'll show you how to build a Twitter clone app using React Navigation v5 and Paper.
The React Navigation v5 comes with many great improvements compared to previous version. It not only provides a cross-platform native Stack, but also the API was redesigned from the ground up to allow things that were never possible before. Thanks to the component-based API, all of the configuration is happening inside the render method. This means we can access props, state and context and can dynamically change configuration for the navigator.
What is React Native Paper?
React Native Paper is a UI component library that implements MD Guidelines. It allows building beautiful interfaces on Mobile and Web with high-quality cross-platform components. Furthermore, Paper provides you with a full theming support, accessibility, RTL and it will take care of platform adaptation. This means you can focus on building apps with ready to use components instead of reimplementing the boring stuff.
In this guide, we would like to show you how to integrate React Navigation with Paper's components. To show all the details of the integration we've decided to build a clone of Twitter. Of course, the functionalities will be very limited but the navigation part and main screens should look and feel similar.
In the following gif, you can see what is the final version of the app gonna looks like:
Overview of the App
Since original Twitter is a very complex app, we will build only a part of it. This means we will implement:
- Stack Navigator with two screens: Screen showing bottom navigation and Details of a tweet
- Bottom navigation with 3 tabs: Feed, Notifications, and Messages
I will focus this guide on a React Navigation and React Native Paper integration. It means I won't show you how to build all of the components necessary to create such an app, but you can always check the full implementation in the github repo.
Let's get started!
I assume you already have an Expo project running locally. If not, make sure to create one. I chose Expo over plain React-Native because it includes most of the dependencies that we need so there is less work to do for us.
Let's install React Native Paper, React Navigation v5 and other required dependencies.
In the next step we will make sure versions of these libraries are compatible.
After you run these two commands you should be ready to go. Let's start implementing the app!
React Navigation and React Native Paper initial setup.
Both these libraries require minimal setup.
In case of React Native Paper, we need to wrap the component tree with a Provider. You can do this inside the exported component in the App.js file.
The PaperProvider provides the theme to all the components in the framework. It also acts as a portal to components that need to be rendered at the top level. Check the full Getting-Started page for more information.
React Navigation setup looks similar. There is a component called NavigationContainer which manages our navigation tree and contains the navigation state. It must wrap all navigator structure. We will render this component in App.tsx inside a PaperProvider. More information can be found in the official documentation.
In our Twitter clone, we want to implement a Drawer that is available from any screen in the app. This means it has to be a topmost navigator.
In React Navigation v5 there is a common pattern for creating navigators. After importing createXNavigator function from the navigator package of your choice you can use Navigator and Screen components from the value it returns.
So let's create a basic version of a Drawer:
That's what we see on a screen:
We can open a drawer with a swipe gesture, it looks very smooth. However, the UI doesn't look very impressive so let's add more content to the drawer to make it look just like in the final version.
We will use:
- DrawerContentScrollView and DrawerItem from @react-navigation/drawer
- Avatar, Text and Switch from react-native-paper
DrawerContentScrollView component makes the drawer vertically scrollable and provides support for devices with notches, so it's highly recommended to use it even for custom drawers.
Components from React Native Paper make a clean, material UI.
The final version of a drawer looks like this:
Stack Navigator + Paper's Appbar
Stack Navigator provides a way for an app to transition between screens when each new screen is placed on top of a stack. In case of this Twitter clone, we will use it to transition from a screen displaying a feed of tweets to the screen showing details of a tweet.
React Navigation v5 provides two implementations of a Stack Navigator
- Native Stack
- JS-based Stack
The main difference between them is that JS-based stack re-implements animations and gestures while the native stack navigator relies on the platform primitives for animations and gestures.
In this section, we will integrate React Native Paper Appbar and JS-based Stack Navigator.
As a first step, we will create a minimal version of a Stack:
By default, the stack navigator is configured to have the familiar iOS and Android header. That doesn't suit our needs, because we want to use Paper's Appbar instead.
We can achieve that by passing an
Appbar.Header component as a
header in Stack's
screenOptions. We will also pass a
headerMode prop with a value of
screen to have a nice looking fade in/out animation.
The Function that we pass to
header prop has access to 3 properties:
Thanks to the scene property we can access the title of topmost screen on the stack and display it in the header. Previous property tells us if there are any other screens lower on the Stack.
Finally, **navigation** property allows navigating to different screens e.g. opening a Drawer.
The thing that we haven't covered yet and it is very important is how to actually navigate between Stack Navigator screens. In case of Tab or Drawer Navigator, we get it out of the box. We can swipe to open/close the Drawer or press a tab to change the scene. In Stack, we have to implement it by ourselves.
React Navigation gives us many different ways to navigate, but we will mostly focus on
pop. You can access these two methods in navigation prop.
As the name suggests
push method pushes the new screen on the stack and
pop removes current screen from the stack.
As you can see on a snippet above, we invoke a
navigation.pop function whenever user presses the back button in header. This means user will be allowed to come back from Details to the Feed screen.
We still need to implement an option to go from Feed to the Details. We can do it by invoking
navigation.push('Details') whenever user presses a Tweet.
The implementation of
Details components is quite big and complex, that's why I am not gonna post it here. Please make sure to check it out on github repo
We have covered only the basics of navigating between screens. If you want to learn more details check the official documentation.
Now, let's see what does the app looks like with Stack Navigator and Paper's Appbar.
We still miss the last piece of our navigation flow - Tab Navigator. Let's move to the next section where we will take care of it.
In this section, we will implement a Tab Navigator with 3 tabs and we will make sure this component is now a one of Stack's screen.
We will use a Bottom Navigation component from React Native Paper that is exposed via @react-navigation/material-bottom-tabs package.
Let's import the createMaterialBottomTabNavigator function first.
Then we can get a reference to the Tab.Navigator and Tab.Screen components.
Now, we are ready to build the actual Bottom Navigation. We will render a
Tab.navigator and 3
Tab.Screen components as children. Each
Tab.Screen representing a tab.
When we check the screen of the phone now, we will see a nice looking, material bottom navigation. What's more, Stack Navigator integrates nicely with Tab.Navigator and we can still navigate to the tweet
FAB and Portal
As it is stated in Material Design Guidelines, the purpose of the FAB button is to give easy access to the main action of the application. Of course, the official Twitter app follows this pattern. Based on the type of screen, it allows creating new tweets or sending direct messages via FAB. It also smoothly animates the icon of the FAB when the user changes the tab and hides the FAB completely on specific screens.
Portal allows rendering a component at a different place in the parent tree. It means you can use it to render content that should appear above other elements, similar to Modal.
As an initial step, we will render a FAB on all tabs and then we will add additional functionalities.
Let's render a
Portal in the same component where we render Tabs:
With just a few lines of JSX we have a nice looking FAB displayed on all tabs. Let's implement hiding it whenever the user goes to the tweet details screen.
Our current navigation structure should be:
- StackNavigator that has two screens
- The First screen of StackNavigator renders a TabNavigator with 3 tabs
- The Second screen of StckNavigator renders a Tweet details
This means a component that renders TabNavigator is a Stack's screen. Thanks to that, we can use
useIsFocused hook provided by
@react-navigation/native and conditionally hide
In the last step we will add ability to show different icon depending on the active tab.
We will take an advantage of our
BottomTabs component being one of a Stack's screen. It means it has an access to the
route object that is passed to each screen as a prop. This object contains an information about current screen which means we can access it and conditionally render proper icon. This is not a very common pattern and it can be confusing at first, so make sure to read the whole guide on how to use it and what can be achieved by using it.
As you can see on the gif, the FAB button works in the same way as in a Twitter app. What's more, it even animates icon change properly even though we haven't implemented it. That's the behavior we get from React Native Paper's FAB out of the box.
Nowadays, supporting the Light/Dark theme is no longer a fancy way to stand out from other apps, but it has become a standard. Happily, both React Navigation v5 and React Native Paper supports theming and in this section I'll guide you through setting it up.
React Navigation exports two themes:
We can import them from
@react-navigation/native package and pass to
NavigationContainer to apply the theme:
React Native Paper
React Native Paper similarly to React Navigation also exports two themes:
Once we import a theme we can pass it to the Paper's
Since both React Navigation and React Native Paper follows the same pattern for theming and structure of the theme object is very similar, we can combine them into one object:
If code for themes merging looks complex, you can use a deepmerge package. It will simplify the implementation significantly.
Of course, the built-in themes are not the only themes we can apply. Both libraries allow full customization and you can learn about it in the official documentation (React Navigation, React Native Paper)
In the last step, I want to show you how to change the theme dynamically. We will implement a switch in a drawer that will allow users choosing light or dark theme.
We need to store information about the currently selected theme somewhere. The local state of the root component sounds reasonable. Also, we will conditionally pass different themes based on the state.
As you remember, we already render a Switch in a Drawer, but we haven't implemented any logic when it is pressed. Let's take care of it now:
Firstly, we get a current theme using
useTheme hook from Paper. This means we can check
dark property on it and pass the correct value to
Secondly, we pass a `toggleTheme` function to `TouchableRipple` to toggle theme whenever user presses a Switch.
You should be able to toggle a switch now and both
Provider from Paper and
NativeNavigationContainer from React Navigation will automatically apply correct colors to the components.
We all know that UI Component library like Paper can speed up the development, but integrating it with a navigation can be sometimes not very straighforward. I hope I showed you the most important aspects of this process in this guide. After reading this article, using Paper's BottomNavigation, Appbar, Drawer, FAB or Portal alongside with React Navigation shouldn't be a problem for you.
Do you have any questions? Tweet to me @trensik.