⛵Thousand Ways to Navigate in React Native

This is going to be a looong trip, folks!
This post is a longer version of my lightning talk at react-europe 2017, where I talked about the state of navigation libraries in the React Native ecosystem, and tried to make things even worse by announcing another one…

The Holy Grail 🏆

Navigation is probably the N°1 concern in React Native. The crazy amount of libraries available on NPM is a great example of that (around ~150 packages 😲). This excitement around navigation is due to a failure on React Native’s end…

In fact, React Native itself provides 3 navigation solutions:

  • Navigator, a JS-based solution launched with React Native, but it’s not powerful enough
  • NavigatorIOS, only targets iOS and is not maintained anymore
  • NavigationExperimental, now deprecated

As you can see: none of those are really recommended for production…

NB: To be 100% honest, you can still use Navigator, but bear with me: something more exciting is yet to come!


The Contenders 🤼‍

Thankfully, the community has raised awareness of the need for practical, simple but powerful navigation libraries in React Native. Some of them are doing a great job and should be rewarded for that.

react-navigation

React Navigation seems to be the go-to solution today in most cases. It was built to replace Navigator and NavigationExperimental we mentioned earlier, and even Ex-Navigation from Expo.

“React Navigation is a collaboration between people from Facebook, Exponent and the React community at large”

It’s going to be the official React Native navigation solution as soon as it’s stable enough. So, this is the one you can choose without worrying too much about community support 😉

react-native-router-flux

React Native Router (or react-native-router-flux) has always been a very popular solution since we didn’t have anything that could easily get the job done. The library is still very popular among large amounts of people. But some of them are starting to feel a little bit concerned with this one and are moving to React Navigation because React Native Router is still based on an old version of NavigationExperimental.

Nevertheless, it’s still a robust navigation library you can rely on. The only limitations I’ve faced were when I wanted to heavily customise my navigation bar, title, colours, etc. This is where the API didn’t seem to be the best solution for this kind of use cases.

react-native-navigation 🏅

My 1st Special mention🏅goes to React Native Navigation by Wix. As a matter of fact: this is the most actively maintained React Native navigation library implemented natively.

This means that it just exposes a native API you can use in JavaScript, but all the real work is done on the native thread. So the result is, as you can guess, buttery smooth!

React Native Navigation is currently being rewritten for its v2 with a better API and works on Android and iOS. You should definitely give it a try and see the difference with a JS-based navigation by yourself!

native-navigation 🏅

The 2nd Special mention🏅 goes to Native Navigation by Airbnb. By its name, I assume you know why: this is the other navigation library working on the native thread in React Native.

Native Navigation was announced during React Conf 17 and is still in its early stages. I recommend you watch Leland Richardson’s talk to have in depth explanations of the rationale behind this library. It seems very promising so make sure to visit their GitHub!


What if we push it 1001 🤔 ?

In June 2016 I started working with my good friend Léo Le Bras on an app called Wino 🍷. If this isn’t the first article you read from me, this name might be familiar to you: it was the main topic of my previous article.

Long story short, Wino 🍷 is an iOS app (for now), 100% written in React Native, that helps you find the wine you should buy, according to where and when you’ll be drinking it.

When we were working on it (back in June 2016 then), none of the libraries available at that time really fit our needs…except one:

When the folks at React Training started working on the v4, they came out with something really interesting that resonated with us and fits in 2 words:

Just Components™

This meant -in React Native- that we no longer needed to register all the screens before using them, that every single component could now be considered as a full-fledge route, enabling a level of composability we had never seen before.

And when we talk about routing on ReactJS, in 99,99% of the cases, React Router is the most recommended solution. So what if, as a React developer, you could be able to use the exact same API, on both your Web & mobile apps 🤔?

Unfortunately, React Router Native doesn’t ship with a navigation structure (it doesn’t animate while transiting between 2 screens for instance), so Léo told me:

which I answered by :

So after 10 months of hard work, sweat, tears, famine, and researchs on NPM for an available package name:

🎉 react-router-navigation is here! 🎉

React Router Navigation ⛵️

Here is the idea: keep the Just Components™ spirit of React Router, and just add mobile navigation on top of it. Our n°1 goal was to keep a very similar API between Web & native apps.

React Router Navigation exposes 6 different components, so let’s get right into it:
 1. We have <Navigation />, which renders one screen at a time and provides transitions between screens:


<Navigation
title=”MinionsGo!”
titleStyle={{ color: 'minionYellow' }}
backButtonTitle=”Poopaye!”
>
...
</Navigation>

2. These screens are wrapped into our 2nd component: <Card />. So this is the simplest way to get up and running with React Router Navigation:

<Navigation>
<Card
exact path="/app/feed"
component={Feed}
/>
<Card
backButtonTintColor="minionYellow"
path=`app/feed/article/${id}`
component={Article}
/>
</Navigation>

One or more <Card /> wrapped into a single <Navigation /> which renders a single screen according to the matching path, based on React Router v4 API.

 3. We also have <NavBar /> but you probably won’t need this one as much as the others. But, should you need to tweak the navigation bar, it can be helpful:

<Navigation
renderNavBar={() => (
<View>
<MyCustomSearchBar />
<NavBar {...this.props} />
</View>
)}
>
...
</Navigation>

4 & 5. The next 2 components are quite similar <Tabs /> and <Tab />. They can be very useful when you have to navigate into a tab view:

<Tabs
title="What are you up to tonight 🤔?"
tabIndicatorStyle={{ backgroundColor: 'beer' }}
>
<Tab path="/option1" component={Beer} />
<Tab path="/option2" component={Karaoke} />
<Tab path="/option3" component={ConfigureWebpackBruh} />
</Tabs>

6. Last but not least, the core element of the navigation in a mobile app, <BottomNavigation /> for the bottom navigation bar :

<BottomNavigation>
<Tab
path="/app/home"
label="Home"
renderTabIcon={({ focused }) => (
<BottomNavIcon name="home" activated={focused} />
)}
component={Home}
/>
<Tab
path="/app/search"
label="Search"
renderTabIcon={({ focused }) => (
<BottomNavIcon name="search" activated={focused} />
)}
component={Search}
/>
<Tab
path="/app/profile"
label="Profile"
renderTabIcon={({ focused }) => (
<BottomNavIcon name="profile" activated={focused} />
)}
component={Profile}
/>
</BottomNavigation>

Disclaimer: React Router Navigation uses the latest Material Design guidelines which includes a bottom navigation bar on Android.

The great thing here is how simple and powerful it is, because in the end: we’re Just [using] Components™!

So if you’ve already written a React JS or React Native app: you already know how to use React Router Navigation! Now, let me give you some real-world examples.


Root

This is how we could declare our main navigation, very straightforward as you can see. Here is the logic behind this: my app starts with a /launch route, where I can write the logic to very if my user is logged in or not in the <Launch /> component.

After that I know if I should redirect the user on the /app route, or the /auth and then the /welcome route. Quite easy, isn’t it?


Auth

You can see that there is a bunch of interesting stuff in this piece of code.

First of all, don’t get disturbed by my several imports, it’s just to make it easier to understand the nature of each variables I’m using.

So let’s start with <Navigation />. Subtle but important detail: here I can define props that impact every <Card /> inside of it. Example: the navBarStyle prop.

You’ll also noticed that <Image /> is outside <Navigation /> because it’s actually displayed in all my screens, so I don’t have to duplicate it 3 times in each one of them. The result is right there: a single <Image /> component, displayed in several routes.


Link

When we want to navigate into the app, we’ll just use <Link /> from React Router Native as described in the doc, or the history prop you saw in my Auth example lines 24 & 32 (don’t worry I knew you would ask about it 😄).

BottomNavigation

Finally, our <BottomNavigation /> component where we can render each tab lazily, and where each tab has its own label, icon, style, etc.

Here we redirect our /app route to /app/home and we use <Switch /> from React Router to switch between these 2 routes. Now we can use <Tab /> for bottom navigation bar elements and even decide how to render our icons depending on the focus state.


As promised: I showed nothing but components.

That’s pretty much everything you need to master React Router Navigation. No complex functions or stuff like that: Just Components™. You can now try it by yourself and see if React Router Navigation enhances your workflow as it did mine.

If you were wondering about the props exposed by React Router Navigation, here are some of them:

NB: Some components like <Tabs /> or <Tab /> have specific props (eg: focused with <Tab />).


Shoutouts 📣

React Router Navigation uses React Router/React Router Native, React Navigation and React Native Tab View under the hood to handle navigation, transitions, tab bars, routing, deep linking, and a bunch of other cool stuff like that. So huge thanks to every single person working on these libraries!

Obviously, huge shoutout to my MVP Léo Le Bras 👏 who is clearly the brains behind React Router Navigation! To be honest, my role here can be summed up by this very GIF:

Yeah: celebrate after each successful release 🕺

We’re still polishing this v1 and planning to switch to a native implementation for the v2. So if we’ve drawn your attention, make sure to chime in on Twitter or GitHub! 🍻