House
/
Blog
/
Explore Expo Router Alpha
React Native

Explore Expo Router Alpha

By following along this blog post, you will learn how to build a social media type application with TypeScript, Expo and particularly the Expo Router package. We will be starting from a boilerplate provided by expo as a quick starting point before going on to introduce Expo Router’s file based routing. Then we will look into adding a nested tab navigator and finally see how this package automatically enables deeplinking to all routes.

Explore Expo Router Alpha

Intro

I don’t know about you but for me, react-native has been a game changer in productivity. After doing native development for a while, react-native feels like native development on steroids and it goes without saying that using Expo feels like react-native on steroids! The way Expo streamlines the developer experience is simply out of this world and there are very few remaining aspects of generic app development problems that they have not improved. Expo Router package is yet another example of that. This is very early days for the package but I am already onboard the hype train and believe that this is the future of routing for react-native apps. I’ve used every run-of-the-mill routing package with react-native apps and even with the beta version, Expo Router feels like it’s way ahead of all of them. Under the hood, it uses react-navigation library but the improved developer experience on top of it is great added value.

Hopefully, by the end of this post, you will be feeling the hype and agree that this package is going to change developer productivity when it comes to wrangling routing/navigation on any app of any scale.

Before we dive in, if you’re like me and prefer seeing the code first before committing to reading a long blog post, all the code we’re gonna write throughout this post can be found here, on this github repo.

To dig into the package, we’re going to build a social media style app named Soci where 

  1. Multiple posts are shown on the home feed
  2. Each post have reactions and comments
  3. As users tap on the post, they are taken to comments on the post
  4. As users tap on dedicated comments or reactions post, they are taken to dedicated screens for comments and reactions

Building this app will allow us to explore some of the most used features of any routing/navigation system:

  1. Stack and Tab navigation
  2. Screen/Router parameters
  3. Nested routes/screens

Since the primary focus of this post is to introduce Expo Router package, we are going to sort of brush over the other aspects of building apps like this such as data fetching, code organization etc.

Initial Setup

At the time of writing this post, the package is in early beta and if you’re familiar with how fast Expo moves with their development, you probably know that this means they will have some breaking changes down the road. So, this package is not recommended for production use. However, that doesn’t mean it’s complicated in any way to get rolling with this. As usual, Expo team already released a starter template with the router that can be used to quickly get an expo app with the router already set up.

A few things to note before we start coding:

  1. You should already have your local machine setup for react-native and Expo development. If not, please follow the official guide from expo to get everything set up.
  2. I am going to be using macOS for development and an iOS simulator for manual testing but feel free to use whatever is the easiest for you since expo allows you to develop from any OS and test on any OS. 

To create our app, we need to simply run the below command in a terminal window

It will ask you a question or two and based on your answers, it will drop in all the necessary things for us to start building on. When asked the name of the app, I answered soci. You can input whatever you want but this input will play a role down the road so please keep that in mind.

After the command completes, you should have a directory with a basic expo app inside of it. The generated app uses plain JavaScript but I can’t write application code without TypeScript these days so I’m going to drop in TypeScript but you can ignore this step if you’d like. 

Navigate into the directory from the terminal window and create a tsconfig.json file by simply running

Expo is smart enough to figure out that we want TypeScript just by seeing this config file in the root of the project so, as soon as you boot up the app now, expo will ask you if you’d like to set the project up to use TypeScript and answering positively will take care of the rest. So, now, go ahead and run `yarn ios` in the terminal window and answer `y` when prompted. When the rest of the command completes, you should see an iOS simulator start with the app.

Finally, we are going to rename the `index.js` file to `index.tsx` file at the root of the project to remove the last trace of plain JavaScript from the codebase. The content inside of it can remain the same.

Layout and stack routes

Most react-native routing libraries out there use imperative code to set up routing/navigation hierarchy and in combination with React’s declarative style, things become confusing, very fast, as to, where to put bootstrapping navigation code? Where do layouts go? Where do shared screens go? Expo Router package answers these questions very elegantly: React Components.

Expo Router uses file system based navigation which means most of the configuration happens by simply creating a file in the right place within the codebase. By default, Expo Router will use the `app/` directory to look for these files. So, let’s create a new directory named `app` in the root of the project and add 2 files inside of it: 

  1. `_layout.tsx` -> This is a special file which should only contain the layout of all route files contained within the directory. Since we are creating it at the root of `app/` directory, it implies that this layout will be used for global routing of the whole app.
  2. `index.tsx` file -> This is also a special file because any index file inside a directory will be used as the default route for that directory. Since we are creating it at the root of `app/` directory, it implies that this is the entry/landing screen of the app.

Now, we want our app’s default navigation to be stack based and for that, all we need is the below code inside the `app/_layout.tsx` file

This automatically sets up a stack navigator which will be used as the root navigator of the app. Any option you can pass to the stack navigator from react-navigation can be passed to the `<Stack />` component.

Then, let’s fill up the `app/index.tsx` file with the below code

Expo Router will automatically drop in this component as the main screen of the root navigator and in fact, if you check your simulator now, you should see the screen’s header show the title `Home`, thanks to the option `title: “Home”` passed to the `<Stack.Screen />` component. At the surface level, this doesn’t look like much and may look rather tedious to have to create 2 files just to get 1 screen. However, this approach allows us to abstract out the bootstrapping into its dedicated file while keeping the screen level control isolated within each screen’s dedicated file, making the separation of concern much easier to manage as your app grows.

Mimic social media app’s data

This part of the work is only done to mimic a generic social media app’s UX so we will quickly go through this as boilerplate setup and not go into further details.

First, create a `data.ts` file at the root of the project and paste in the below code:

Normally, you would have your app fetch this data from a server somewhere but that’s outside of the scope of this post so I’m simply dropping in static data into this file and adding a couple of helper functions to extract comments and reactions from a post’s id.

Now, take the following code and replace everything inside of `app/index.tsx` file with it

A quick overview of what’s happening here

  1. Iterate upon the list of posts and showing the title, content and total count of comments and reactions as buttons for each post.
  2. Each post item is tappable and when tapped, users will be taken to the comments screen for that post. This is done by using the handy `useLink()` hook provided by the Expo Router package which allows us to move to a screen just like you would in a browser using url. Please pay close attention to the syntax here `link.push(`/post/${post.id}/comments`)` because the “url” here is what tells expo which screen to go to and we will later see how this url is reflected in the route file’s location.
  3. For the Reactions and Comments buttons, we are using the `<Link>` component which is kind of like the `<a>` tag in browser because when tapped, this component will take the user the the route based on the `href` prop passed to this component.

Nested routes and route params

As of now, if you interact with any of the posts we are showing on the home screen of the app, you will be greeted with a generic, `page not found` screen because we haven’t set up those screens yet. Let’s get that done now. 

For each post, we are going to set up a tab navigator with 2 tabs: Reactions and Comments. First, create a file `app/post/_layout.tsx` and put the following code inside of it:

Remember that `_layout.tsx` files determine how the entire layout of the entire directory’s screens is going to be. So, here, for posts, we are setting up a `Tab` navigator with 2 screens inside. Each screen takes a unique name and all options that a tab navigator screen can take from react-navigation library. The additional `href` property takes the URL where the user is routed to when they tap the tab buttons at the bottom of the screen. Also, since each post will be opened with their ids, we can fetch it directly from the `route.params` object. The `name` prop determines how Expo Router maps each of these screens to a screen file in the file system.

Now, let’s build the individual screens inside the navigator. Create a new file in `app/post/[id]/comments.tsx`. Notice the special directory name `[id]`. This tells Expo Router that these screens will have a dynamic route param named `id`. Now, put the following code inside that file:

This component expects the `route.params.id` to contain the id of the post which the user tapped on to arrive on this screen. Using the id, we’re fetching all comments on that post and iterating over the comments to display them on the screen.

Similarly, create another file in `app/post/[id]/reactions.tsx` and put the following content inside of it:

Similar to the comments screen, we are fetching all reactions for a post using the post id from the route params and iterating over them to display them on screen.

With all of that, you should now be able to navigate around the app by tapping on posts or reactions button or comments button. Here’s a quick preview of how all of it looks on iOS simulator:

Automatic Deeplinks

One of the coolest features that Expo Router provides out of the box is automated deep linking. If you’ve ever set up deep linking for a react-native app, you know how painful the developer experience is. In the app we just built, internally, the URLs used for navigating around the app are also available as deep links. So, when we use `link.push(‘/post/1/comments’)` to go to a screen, it means that URL is also available as a deep link and will open that same screen when triggered from outside of the app.

During the initial set up, Expo asks to pick the name of the app and that name is used as the deeplinking scheme. If you open the `app.json` file, and look at the `”scheme”` property, the value of that property will be your app’s base scheme that will be used to build any deep link. For my set up, it looks like `”scheme”: “soci”` so, following the above example, if I open `soci://post/1/comments` it will open up the comments screen for the post with id 1. To quickly test deeplink on iOS simulators, you can run the following command

Closing Thoughts

Since the Expo Router is built on top of the react-navigation library, it can do everything react-navigation can do. What I’ve tried to cover throughout this post are the interesting bits that Expo Router sprinkles on top of react-navigation. There are some more amazing concepts that Expo Router introduces such as shared routes or how errors are handled or modals are displayed and I’m sure the team will bring out more innovative ideas as the development advances and I hope that like me, you are excited to use this in a real world, production-grade application.

House
/
Blog
/
React Native

Explore Expo Router Alpha

/
Explore Expo Router Alpha
By following along this blog post, you will learn how to build a social media type application with TypeScript, Expo and particularly the Expo Router package. We will be starting from a boilerplate provided by expo as a quick starting point before going on to introduce Expo Router’s file based routing. Then we will look into adding a nested tab navigator and finally see how this package automatically enables deeplinking to all routes.

Intro

I don’t know about you but for me, react-native has been a game changer in productivity. After doing native development for a while, react-native feels like native development on steroids and it goes without saying that using Expo feels like react-native on steroids! The way Expo streamlines the developer experience is simply out of this world and there are very few remaining aspects of generic app development problems that they have not improved. Expo Router package is yet another example of that. This is very early days for the package but I am already onboard the hype train and believe that this is the future of routing for react-native apps. I’ve used every run-of-the-mill routing package with react-native apps and even with the beta version, Expo Router feels like it’s way ahead of all of them. Under the hood, it uses react-navigation library but the improved developer experience on top of it is great added value.

Hopefully, by the end of this post, you will be feeling the hype and agree that this package is going to change developer productivity when it comes to wrangling routing/navigation on any app of any scale.

Before we dive in, if you’re like me and prefer seeing the code first before committing to reading a long blog post, all the code we’re gonna write throughout this post can be found here, on this github repo.

To dig into the package, we’re going to build a social media style app named Soci where 

  1. Multiple posts are shown on the home feed
  2. Each post have reactions and comments
  3. As users tap on the post, they are taken to comments on the post
  4. As users tap on dedicated comments or reactions post, they are taken to dedicated screens for comments and reactions

Building this app will allow us to explore some of the most used features of any routing/navigation system:

  1. Stack and Tab navigation
  2. Screen/Router parameters
  3. Nested routes/screens

Since the primary focus of this post is to introduce Expo Router package, we are going to sort of brush over the other aspects of building apps like this such as data fetching, code organization etc.

Initial Setup

At the time of writing this post, the package is in early beta and if you’re familiar with how fast Expo moves with their development, you probably know that this means they will have some breaking changes down the road. So, this package is not recommended for production use. However, that doesn’t mean it’s complicated in any way to get rolling with this. As usual, Expo team already released a starter template with the router that can be used to quickly get an expo app with the router already set up.

A few things to note before we start coding:

  1. You should already have your local machine setup for react-native and Expo development. If not, please follow the official guide from expo to get everything set up.
  2. I am going to be using macOS for development and an iOS simulator for manual testing but feel free to use whatever is the easiest for you since expo allows you to develop from any OS and test on any OS. 

To create our app, we need to simply run the below command in a terminal window

It will ask you a question or two and based on your answers, it will drop in all the necessary things for us to start building on. When asked the name of the app, I answered soci. You can input whatever you want but this input will play a role down the road so please keep that in mind.

After the command completes, you should have a directory with a basic expo app inside of it. The generated app uses plain JavaScript but I can’t write application code without TypeScript these days so I’m going to drop in TypeScript but you can ignore this step if you’d like. 

Navigate into the directory from the terminal window and create a tsconfig.json file by simply running

Expo is smart enough to figure out that we want TypeScript just by seeing this config file in the root of the project so, as soon as you boot up the app now, expo will ask you if you’d like to set the project up to use TypeScript and answering positively will take care of the rest. So, now, go ahead and run `yarn ios` in the terminal window and answer `y` when prompted. When the rest of the command completes, you should see an iOS simulator start with the app.

Finally, we are going to rename the `index.js` file to `index.tsx` file at the root of the project to remove the last trace of plain JavaScript from the codebase. The content inside of it can remain the same.

Layout and stack routes

Most react-native routing libraries out there use imperative code to set up routing/navigation hierarchy and in combination with React’s declarative style, things become confusing, very fast, as to, where to put bootstrapping navigation code? Where do layouts go? Where do shared screens go? Expo Router package answers these questions very elegantly: React Components.

Expo Router uses file system based navigation which means most of the configuration happens by simply creating a file in the right place within the codebase. By default, Expo Router will use the `app/` directory to look for these files. So, let’s create a new directory named `app` in the root of the project and add 2 files inside of it: 

  1. `_layout.tsx` -> This is a special file which should only contain the layout of all route files contained within the directory. Since we are creating it at the root of `app/` directory, it implies that this layout will be used for global routing of the whole app.
  2. `index.tsx` file -> This is also a special file because any index file inside a directory will be used as the default route for that directory. Since we are creating it at the root of `app/` directory, it implies that this is the entry/landing screen of the app.

Now, we want our app’s default navigation to be stack based and for that, all we need is the below code inside the `app/_layout.tsx` file

This automatically sets up a stack navigator which will be used as the root navigator of the app. Any option you can pass to the stack navigator from react-navigation can be passed to the `<Stack />` component.

Then, let’s fill up the `app/index.tsx` file with the below code

Expo Router will automatically drop in this component as the main screen of the root navigator and in fact, if you check your simulator now, you should see the screen’s header show the title `Home`, thanks to the option `title: “Home”` passed to the `<Stack.Screen />` component. At the surface level, this doesn’t look like much and may look rather tedious to have to create 2 files just to get 1 screen. However, this approach allows us to abstract out the bootstrapping into its dedicated file while keeping the screen level control isolated within each screen’s dedicated file, making the separation of concern much easier to manage as your app grows.

Mimic social media app’s data

This part of the work is only done to mimic a generic social media app’s UX so we will quickly go through this as boilerplate setup and not go into further details.

First, create a `data.ts` file at the root of the project and paste in the below code:

Normally, you would have your app fetch this data from a server somewhere but that’s outside of the scope of this post so I’m simply dropping in static data into this file and adding a couple of helper functions to extract comments and reactions from a post’s id.

Now, take the following code and replace everything inside of `app/index.tsx` file with it

A quick overview of what’s happening here

  1. Iterate upon the list of posts and showing the title, content and total count of comments and reactions as buttons for each post.
  2. Each post item is tappable and when tapped, users will be taken to the comments screen for that post. This is done by using the handy `useLink()` hook provided by the Expo Router package which allows us to move to a screen just like you would in a browser using url. Please pay close attention to the syntax here `link.push(`/post/${post.id}/comments`)` because the “url” here is what tells expo which screen to go to and we will later see how this url is reflected in the route file’s location.
  3. For the Reactions and Comments buttons, we are using the `<Link>` component which is kind of like the `<a>` tag in browser because when tapped, this component will take the user the the route based on the `href` prop passed to this component.

Nested routes and route params

As of now, if you interact with any of the posts we are showing on the home screen of the app, you will be greeted with a generic, `page not found` screen because we haven’t set up those screens yet. Let’s get that done now. 

For each post, we are going to set up a tab navigator with 2 tabs: Reactions and Comments. First, create a file `app/post/_layout.tsx` and put the following code inside of it:

Remember that `_layout.tsx` files determine how the entire layout of the entire directory’s screens is going to be. So, here, for posts, we are setting up a `Tab` navigator with 2 screens inside. Each screen takes a unique name and all options that a tab navigator screen can take from react-navigation library. The additional `href` property takes the URL where the user is routed to when they tap the tab buttons at the bottom of the screen. Also, since each post will be opened with their ids, we can fetch it directly from the `route.params` object. The `name` prop determines how Expo Router maps each of these screens to a screen file in the file system.

Now, let’s build the individual screens inside the navigator. Create a new file in `app/post/[id]/comments.tsx`. Notice the special directory name `[id]`. This tells Expo Router that these screens will have a dynamic route param named `id`. Now, put the following code inside that file:

This component expects the `route.params.id` to contain the id of the post which the user tapped on to arrive on this screen. Using the id, we’re fetching all comments on that post and iterating over the comments to display them on the screen.

Similarly, create another file in `app/post/[id]/reactions.tsx` and put the following content inside of it:

Similar to the comments screen, we are fetching all reactions for a post using the post id from the route params and iterating over them to display them on screen.

With all of that, you should now be able to navigate around the app by tapping on posts or reactions button or comments button. Here’s a quick preview of how all of it looks on iOS simulator:

Automatic Deeplinks

One of the coolest features that Expo Router provides out of the box is automated deep linking. If you’ve ever set up deep linking for a react-native app, you know how painful the developer experience is. In the app we just built, internally, the URLs used for navigating around the app are also available as deep links. So, when we use `link.push(‘/post/1/comments’)` to go to a screen, it means that URL is also available as a deep link and will open that same screen when triggered from outside of the app.

During the initial set up, Expo asks to pick the name of the app and that name is used as the deeplinking scheme. If you open the `app.json` file, and look at the `”scheme”` property, the value of that property will be your app’s base scheme that will be used to build any deep link. For my set up, it looks like `”scheme”: “soci”` so, following the above example, if I open `soci://post/1/comments` it will open up the comments screen for the post with id 1. To quickly test deeplink on iOS simulators, you can run the following command

Closing Thoughts

Since the Expo Router is built on top of the react-navigation library, it can do everything react-navigation can do. What I’ve tried to cover throughout this post are the interesting bits that Expo Router sprinkles on top of react-navigation. There are some more amazing concepts that Expo Router introduces such as shared routes or how errors are handled or modals are displayed and I’m sure the team will bring out more innovative ideas as the development advances and I hope that like me, you are excited to use this in a real world, production-grade application.

About the Author
React

Hire vetted remote developers today

Technology leaders rely on G2i to hire freelance software developers, find full-time engineers, and build entire teams.

Group

More from G2i