Skip links
react native application

Deep Linking Integration in React Native Application

Deep linking is a pivotal technique in mobile app development. It directs users to specific screens within an app through designated URLs or resources. Deep linking improves user experience by directing them to specific screens, even within complex app structures, rather than just launching the app. It seamlessly guides users to targeted destinations via designated URLs or resources. This functionality holds immense value in diverse domains such as marketing campaigns and user retention strategies. As a common user scenario, encountering deep linking often happens when clicking on a link, like a product in an e-commerce platform, redirecting users directly to the corresponding screen within the app if installed.

In this blog, we’ll look into implementing deep linking within a React Native application. Through an illustrative example, we’ll construct a basic app equipped to handle deep linking and explore the configuration process using the React Navigation library.

Getting Started

To initiate our journey, let’s begin by generating a fresh React Native project:

npx react-native init DeepLinkProject

Moving forward, proceed to install the necessary dependencies for React Navigation:

yarn add @react-navigation/native
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

We'll also need to install the 'react-navigation/stack' package, which serves as our navigation solution:

yarn add @react-navigation/stack

Configuring Deep Linking with React Navigation

For integrating deep linking, we'll leverage React Native's Linking API. Additionally, we'll employ the useEffect hook to manage deep links effectively. Begin by establishing the Stack Navigator within our App.tsx file:

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Text, View } from 'react-native';

const Stack = createStackNavigator();

function HomeScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>
    </View>
  );
}

function ProfileScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Profile Screen</Text>
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

We've developed two screens: HomeScreen and ProfileScreen. Now, it's time to integrate deep linking into these screens.

Initially, we'll craft a useEffect hook within the App component to manage deep links. Within this hook, we'll incorporate an event listener to Linking, enabling the parsing of incoming URLs and navigation to the appropriate screen:

import * as React from 'react';
import { Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Text, View } from 'react-native';

const Stack = createStackNavigator();

function HomeScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>
    </View>
  );
}

function ProfileScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Profile Screen</Text>
    </View>
  );
}

export default function App() {
  React.useEffect(() => {
    const handleDeepLink = ({ url }: { url: string }) => {
      const route = url.replace(/.*?:\/\//g, '');
      const routeName = route.split('/')[0];

      if (routeName === 'profile') {
        const username = route.split('/')[1];
        navigation.navigate('Profile', { username });
      }
    };

    Linking.addEventListener('url', handleDeepLink);

    return () => {
      Linking.removeEventListener('url', handleDeepLink);
    };
  }, []);

  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Profile"
          component={ProfileScreen}
          options={({ route }) => ({ title: route.params.username })}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Within the useEffect hook, we initially define a function named handleDeepLink to manage the incoming deep link. This function extracts the route name along with any parameters from the URL and then navigates to the corresponding screen using navigation.navigate.

Subsequently, in the ProfileScreen component, we can access the username parameter via route.params.username and utilize it to set the screen's title via the options prop.

Folder Structure

MyProject/
├─ __tests__/
├─ android/
├─ ios/
├─ src/
│ ├─ screens/
│ │ ├─ HomeScreen.tsx
│ │ ├─ ProfileScreen.tsx
│ ├─ App.tsx
├─ package.json

We'll maintain our React Navigation stack within the App.tsx file, while dedicating separate files for each screen within the screens folder.

Full Code

Below is the complete code for the application.

App.tsx

import * as React from 'react';
import { Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Text, View } from 'react-native';

import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';

const Stack = createStackNavigator();

export default function App() {
  React.useEffect(() => {
    const handleDeepLink = ({ url }: { url: string }) => {
      const route = url.replace(/.*?:\/\//g, '');
      const routeName = route.split('/')[0];

      if (routeName === 'profile') {
        const username = route.split('/')[1];
        navigation.navigate('Profile', { username });
      }
    };

    Linking.addEventListener('url', handleDeepLink);

    return () => {
      Linking.removeEventListener('url', handleDeepLink);
    };
  }, []);

  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Profile"
          component={ProfileScreen}
          options={({ route }) => ({ title: route.params.username })}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

screens/HomeScreen.tsx

import * as React from 'react';
import { View, Text, Button } from 'react-native';

interface Props {
  navigation: any;
}

export default function HomeScreen({ navigation }: Props) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Profile"
        onPress={() => navigation.navigate('Profile', { username: 'johndoe' })}
      />
    </View>
  );
}

screens/ProfileScreen.tsx

import * as React from 'react';
import { View, Text } from 'react-native';

interface Props {
  route: any;
}

export default function ProfileScreen({ route }: Props) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Profile Screen</Text>
      <Text>{route.params.username}</Text>
    </View>
  );
}

Conclusion

Within this piece, we've delved into the implementation of deep linking within a React Native application utilizing the React Navigation library. We've thoroughly addressed considerations spanning various platforms and versions, and supplemented our discourse with TypeScript code samples for clarity and applicability across different development environments.

Happy Learning!!