user14263509
user14263509

Reputation:

React Native: How to setup React Navigation types so I don't have to create NavigationProps on each component I use?

So right now I have a routes.tsx file that holds all my types. But on the screens where I use useNavigation() I always need to create a type for it in that component. How do I properly set up a global type for my routes so I don't have to do this?

routes.tsx

export type AuthStackParamList = {
  Landing: undefined;
  GetStarted: undefined;
  VerifyOtp: { email: string };
  PrivacyPolicy: undefined;
  TermsOfService: undefined;
};

export type AppTabParamList = {
  HomeScreen: undefined;
  FriendsScreen: undefined;
  NotificationsScreen: undefined;
  SettingsScreen: undefined;
};

export type OnboardingStackParamList = {
  UsernameScreen: undefined;
};

export type HomeTabStackParamList = {
  Home: undefined;
};

export type FriendsTabStackParamList = {
  Friends: undefined;
  SearchUsers: undefined;
};

export type SettingsTabStackParamList = {
  Settings: undefined;
  EditName: { id: string; name: string };
  EditUsername: { id: string; username: string };
  DeleteAccount: undefined;
};

AuthStack.tsx

const AuthStack = createNativeStackNavigator<AuthStackParamList>();

export function AuthStackNavigator() {
  return (
    <AuthStack.Navigator
      initialRouteName="Landing"
      }}>
      <AuthStack.Screen
        name="Landing"
        component={LandingScreen}
        options={{ headerShown: false }}
      />
      <AuthStack.Screen
        name="GetStarted"
        component={GetStartedScreen}
        options={{ headerTitle: '' }}
      />
      <AuthStack.Screen
        name="VerifyOtp"
        component={VerifyOTPScreen}
        options={{ headerShown: false, gestureEnabled: false }}
      />
      <AuthStack.Screen
        name="TermsOfService"
        component={TermsOfServiceScreen}
        options={{ headerTitle: 'Terms of Service' }}
      />
      <AuthStack.Screen
        name="PrivacyPolicy"
        component={PrivacyPolicy}
        options={{ headerTitle: 'Privacy Policy' }}
      />
    </AuthStack.Navigator>
  );
}

GetStartedScreen.tsx

This is what I want to avoid having to do whenever I need to tap into useNavigation

type GetStartedScreenNavigationProps = NativeStackNavigationProp<
  AuthStackParamList,
  'GetStarted'
>;

const GetStartedScreen = () => {
  const navigation = useNavigation<GetStartedScreenNavigationProps>();

Upvotes: 3

Views: 242

Answers (3)

Tayyab Mazhar
Tayyab Mazhar

Reputation: 1712

You could create a custom hook in a separate file like this:

export const useAuthStackNavigation = <K extends keyof AuthStackParamList>() =>
{
  return useNavigation<NativeStackNavigationProp<AuthStackParamList, K>>(); 
};

And then in your screen:

const GetStartedScreen = () => {
  const navigation = useAuthStackNavigation<'GetStarted'>();

Upvotes: 0

nbjorling
nbjorling

Reputation: 114

According to the docs a declare global should work with useNavigation.

Instead of manually annotating these APIs, you can specify a global type for your root navigator which will be used as the default type.

To do this, you can add this snippet somewhere in your codebase:

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

The RootParamList interface lets React Navigation know about the params accepted by your root navigator. Here we extend the type RootStackParamList because that's the type of params for our stack navigator at the root. The name of this type isn't important.

Here is a link to the chapter: https://reactnavigation.org/docs/typescript/#specifying-default-types-for-usenavigation-link-ref-etc

Upvotes: 0

Harsh Kukarwadiya
Harsh Kukarwadiya

Reputation: 518

I think there is no way to do that. Because useNavigation is a hook. And a hook is always have to be created inside any component. You can't create the hook and export it to use in any other component.

Upvotes: 0

Related Questions