Jyoti Luhana
Jyoti Luhana

Reputation: 31

React Native: Deep linking doesn't work properly with StackNavigator

I am trying deeplinking in React-Native. The code works properly when the app is in the background. But once I remove the app from background and try to launch it using the link in safari. The app is launched with details screen. But I could not find previous (Home) screens in the Navigation Stack. Please find the code below:

/* eslint-disable react-native/no-inline-styles */
import 'react-native-gesture-handler';
import React from 'react';
import {TouchableOpacity, Text, View} from 'react-native';
import {useLinking, NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';

const HomeScreen = ({navigation}) => {
  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
      }}>
      <Text>Home Screen</Text>
      <TouchableOpacity
        onPress={() => {
          navigation.navigate('Details', {itemId: 40});
        }}>
        <Text>Go to Details</Text>
      </TouchableOpacity>
    </View>
  );
};

const DetailScreen = ({route, navigation}) => {
  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
      }}>
      <Text>Details Screen</Text>
      <Text>Item Id: {route.params.itemId}</Text>
      <TouchableOpacity onPress={() => navigation.goBack()}>
        <Text>Go Back</Text>
      </TouchableOpacity>
    </View>
  );
};

const Stack = createStackNavigator();

const App = () => {
  const ref = React.useRef();
  const {getInitialState} = useLinking(ref, {
    prefixes: ['deeplink://'],
    config: {
      initialRouteName: 'Home',
      Home: 'Home',
      Details: {
        path: 'Details/:itemId',
        parse: {
          itemId: null,
        },
      },
    },
    getPathFromState(state, config) {
      console.log(state);
    },
  });

  const [isReady, setIsReady] = React.useState(false);
  const [initialState, setInitialState] = React.useState();

  React.useEffect(() => {
    Promise.race([
      getInitialState(),
      new Promise((resolve) => setTimeout(resolve, 150)),
    ])
      .catch((e) => {
        console.error(e);
      })
      .then((state) => {
        if (state !== undefined) {
          setInitialState(state);
        }
        setIsReady(true);
      });
  }, [getInitialState]);

  if (!isReady) {
    return null;
  }
  return (
    <NavigationContainer
      fallback={<Text>Loading...</Text>}
      initialState={initialState}
      ref={ref}>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

Launched the app using "deeplink://Details/86" in Safari.

Upvotes: 3

Views: 10468

Answers (1)

satya164
satya164

Reputation: 10145

First, update to latest version of @react-navigation/native and then follow the linking docs: https://reactnavigation.org/docs/configuring-links/

Instead of useLinking, you can pass a linking prop to the NavigationContainer component. Then change your config to following:

const App = () => {
  const linking = {
    prefixes: ["deeplink://"],
    config: {
      initialRouteName: "Home",
      screens: {
        Home: {
          path: "home",
        },
        Details: {
          path: "details/:itemId"
        }
      }
    }
  };

  return (
    <NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

Then you can open links like deeplink://home or deeplink://details/someid.

Upvotes: 6

Related Questions