Implementing deep linking in React Native: A quick step-by-step guide

Diego Oliveira
Edited by thoughtbot

Introduction

Deep linking is a crucial feature for modern mobile applications. It enables seamless navigation and an improved user experience and allows users to access specific screens or content within an app by clicking on URLs or interacting with external sources like push notifications. In this blog post, we will explore how to implement deeplinking in a React Native application. By the end of it, you will be able to seamlessly integrate deep linking functionality into your app, enabling users to access specific content with just a single tap.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of React Native. Ensure that you have the React Native environment setup or follow the steps provided in the official documentation for your development OS.

Reference repository

To check or run the full implementation of this tutorial please reference the example GitHub Repository. It contains a barebones React Native application with only the implementation explained in this tutorial.

Setting up the React Native project

First, let’s set up a new React Native project using the React Native CLI. Open your terminal and execute the following command:

npx react-native init DeeplinkingExample

This command will create a new project named “DeeplinkingExample” on your current folder.

Installing dependencies

To implement this deep linking example we will use the React Navigation library as it is widely used by the community for handling navigation and deep linking in React Native apps.

Navigate to the project folder:

cd DeeplinkingExample

Next, install the required dependencies:

npm install @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context

The additional libraries are meant to expose the native navigation components and safe-area to React Native.

Update your iOS Pods:

npx pod-install

Setting up basic navigation

In your App.tsx file add the following code. It includes two example screens (Home and Details), accessible through a standard Stack Navigator. The Home screen displays a list of grocery items that when selected take the user to a Details screen that shows the item:

import * as React from "react";
import { Button, View, Text, FlatList, StyleSheet, TouchableOpacity } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

/**
 * Data
 */
const groceryItems = [
  { id: 1, name: "Apples" },
  { id: 2, name: "Bananas" },
  { id: 3, name: "Oranges" },
  { id: 4, name: "Milk" },
  { id: 5, name: "Bread" },
];

/**
 * Screens
 */
function HomeScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>Grocery List</Text>
      {/* FlatList to render the list of grocery items */}
      <FlatList
        style={styles.list}
        data={groceryItems}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => (
          <TouchableOpacity
            style={{ padding: 10, borderBottomWidth: 1 }}
            onPress={() => navigation.navigate("Details", { id: item.id })}
          >
            <Text>{item.name}</Text>
          </TouchableOpacity>
        )}
      />
    </View>
  );
}

function DetailsScreen({ route, navigation }) {
  return (
    <View style={styles.container}>
      <Text>
        Item:
        {groceryItems.find((item) => item.id === Number(route.params.id))
          ?.name ?? "Not Found"}
      </Text>
      <Button title="Back" onPress={() => navigation.goBack()} />
    </View>
  );
}

/**
 * Stack Navigator
 */
const Stack = createNativeStackNavigator();

/**
 * StyleSheet
 */
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  list: {
    width: '100%',
  },
  button: {
    padding: 10,
    borderBottomWidth: 1,
  },
});

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

Integrating deep linking in app entry point

To open the app based on the myapp:// uri run the following command to add the necessary schemes in the native projects:

npx uri-scheme add myapp

The myapp in the uri is an arbitrary and can be changed to any custom name you prefer. The uri-scheme is a stand-alone package by Expo that simplifies the process of editting and setting up uri schemes within the native code.

Linking Navigation

Create a linking configuration object to be added to your navigation container.

/**
 * Linking Configuration
 */
const linking = {
  // Prefixes accepted by the navigation container, should match the added schemes
  prefixes: ["myapp://"],
  // Route config to map uri paths to screens
  config: {
    // Initial route name to be added to the stack before any further navigation,
    // should match one of the available screens
    initialRouteName: "Home" as const,
    screens: {
      // myapp://home -> HomeScreen
      Home: "home",
      // myapp://details/1 -> DetailsScreen with param id: 1
      Details: "details/:id",
    },
  },
};

Then add the linking to your navigation container

<NavigationContainer linking={linking}>
  <Stack.Navigator initialRouteName="Home">
    <Stack.Screen name="Home" component={HomeScreen} />
    <Stack.Screen name="Details" component={DetailsScreen} />
  </Stack.Navigator>
</NavigationContainer>

Testing deep linking

To test deep linking in your React Native application, first run:

npx react-native start

This command starts the Metro server. Next, open another terminal tab and execute:

npx react-native run-android

or

npx react-native run-ios

Ensure that the app is installed and running on your iOS Simulator or Android Emulator. To trigger a deep link, you can use the following commands based on the platform you are running:

For iOS:

xcrun simctl openurl booted "myapp://home"

For Android:

adb shell am start -W -a android.intent.action.VIEW -d "myapp://home"

In our linking configuration we specified a special link capable of taking parameters embedded in the uri and enables you to pass specific navigation params in your deeplink that will be accessible through the screen’s route.param prop.

Details: "details/:id";

In this configuration the id param can be passed in the app’s URI, for instance myapp://details/1, and will be accessible in the DetailsScreen from the route prop route.params.id.

xcrun simctl openurl booted "myapp://details/1"

Congratulations! You have successfully implemented deep linking in your React Native application. Now, your users can access specific screens or content within your app through deep links.

Conclusion

In this tutorial, we learned how to implement deep linking in a React Native application. We configured deep linking, set up the necessary navigation, and handled the deep link URL to navigate to the appropriate screen. By following these steps, you have a basic setup that can be expanded to cover all cases for your application and enhance the user’s experience and engagement by allowing seamless access to specific content within your app. Great work!

Want to go deeper?

Do you have an app concept that needs to be market-ready and scale? Do you need a modern, mobile-first approach to an already existing platform? Learn how thoughtbot can help grow your product.