Home > front end >  Problem typing nested navigators react navigation
Problem typing nested navigators react navigation

Time:11-15

I've got a tab navigator that has Home and Profile as screens. Home is a stack navigator that contains RestaurantDetails and RestaurantList as screens.

I have a Button that is in the RestaurantList screen. I want to navigate to RestaurantDetails.

Button.tsx

const Button = ({name}) => {
  const navigation = useNavigation()
  const onPress = () => {
    navigation.navigate("RestaurantDetails", {name})
  }
  return (
    <TouchableOpacity onPress={onPress}>
    </TouchableOpacity>
   
  )
}

The problem is that typescript complains

Argument of type '["RestaurantDetails", { name: string}]' is not assignable to parameter of type '[screen: "Home", params: NavigatorScreenParams<HomeStackParamList, Readonly<{ key: string; index: number; routeNames: string[]; history?: unknown[] | undefined; routes: NavigationRoute<ParamListBase, string>[]; type: string; stale: false; }>>] | [screen: ...] | [screen: ...] | [screen: ...] | [screen: ...]'.
  Type '["RestaurantDetails", { name: string}]' is not assignable to type '[screen: "Profile", params: undefined]'.
    Type at position 0 in source is not compatible with type at position 0 in target.
      Type '"RestaurantDetails"' is not assignable to type '"Profile"'.

I'm pretty sure the problem is that typescript looks in TRootParamList instead of HomeStackParamList for the RestaurantDetails screen, since if I add RestaurantDetails to TRootParamList typescript stops complaining. However, I am unsure on how to actually stop this problem.

types.ts

import { NavigatorScreenParams } from '@react-navigation/native';

type QueueDetailsParams = {
  name: string
};

type HomeStackParamList = {
  RestaurantDetails: QueueDetailsParams | undefined;
  RestaurantList: undefined
};

type TRootParamList = {
  Home: NavigatorScreenParams<HomeStackParamList>;
  Profile: undefined
};

declare global {
  namespace ReactNavigation {
    interface RootParamList extends TRootParamList {}
  }
}

P.S I know that I can replace my onPress with the below but would rather not do this.

const onPress = () => {
    navigation.navigate("Home", {screen: "RestaurantDetails", params: {name}})
  }

CodePudding user response:

Let me know if importing navigation from props solves your problem, if not we can debug it further:

const Button = ({name,navigation}) => {
  const onPress = () => {
    navigation.navigate("RestaurantDetails", {name})
  }
  return (
    <TouchableOpacity onPress={onPress}>
    </TouchableOpacity>
   
  )
}

CodePudding user response:

When you use the useNavigation hook, you have to type it with the StackNavigationProp and the param list that includes the target screen:

const { navigate } = useNavigation<StackNavigationProp<HomeStackParamList>>();

Then you can use it with any screen in that param list:

navigate('RestaurantList');
  • Related