4

I'm trying to include React Navigation 6.x into a React Native project with Redux and therefore need to be able to access the navigator from outside components.

I'm following this guide (Navigating without the navigation prop) and have essentially the same code as in their example, which functionally works fine:

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

export const navigationRef = createNavigationContainerRef()

export function navigate(name, params) {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
}

However I'm also using Typescript.

React Navigation also have a guide on integrating Typescript (Type checking with TypeScript) which shows how to type the navigation ref itself, which works also fine:

export const navigationRef = createNavigationContainerRef<RootStackParamList>();

There is no example for typing the navigate function though, and I haven't been able to get anything to work.

I thought the solution would be to copy the typing for the navigationRef.navigate() method (defined here) and simply apply it to the wrapper function:

// navigationRef.navigate() typing...
//
// navigate<RouteName extends keyof ParamList>(
//   ...args: undefined extends ParamList[RouteName]
//     ? [screen: RouteName] | [screen: RouteName, params: ParamList[RouteName]]
//     : [screen: RouteName, params: ParamList[RouteName]]
// ): void;


type ParamList = RootStackParamList;
type Navigate = <RouteName extends keyof ParamList>(
  ...args: undefined extends ParamList[RouteName]
    ? [screen: RouteName] | [screen: RouteName, params: ParamList[RouteName]]
    : [screen: RouteName, params: ParamList[RouteName]]
) => void;

export const navigate: Navigate = (name, params) => {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
}

// or...

export const navigate: typeof navigationRef.navigate = (name, params) => {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
}

That unfortunately gives the following error:

Argument of type '[(undefined extends RootStackParamList[RouteName] ? [screen: RouteName] | [screen: RouteName, params: RootStackParamList[RouteName]] : [screen: ...])[0], (undefined extends RootStackParamList[RouteName] ? [screen: ...] | [screen: ...] : [screen: ...])[1]]' is not assignable to parameter of type 'undefined extends RootStackParamList[(undefined extends RootStackParamList[RouteName] ? [screen: RouteName] | [screen: RouteName, params: RootStackParamList[RouteName]] : [screen: ...])[0]] ? [screen: ...] | [screen: ...] : [screen: ...]'.ts(2345)
Perceptic
  • 443
  • 1
  • 7
  • 19

4 Answers4

5

Instead of navigationRef.navigate(name, params), you can try with this

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

export function navigateTo(routeName: string, params?: object) {
  if (navigationRef.isReady()) {
    navigationRef.dispatch(CommonActions.navigate(routeName, params));
  }
}

this works for me

bbaoooo
  • 51
  • 1
  • 3
1

This worked for me

export const navigate = (name: keyof RootStackParamList) => {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name)
  }
}

even better:

export const navigate = (
  name: keyof RootStackParamList,
  params?: StackScreenProps<RootStackParamList>['route']['params']
) => {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params)
  }
}
eyettea
  • 1,376
  • 2
  • 16
  • 35
0

You can reuse the type of navigationRef.navigate

export const navigate: typeof navigationRef.navigate = (name, params) => {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
}
satya164
  • 9,464
  • 2
  • 31
  • 42
  • Thanks that's definitely more succinct, but I get the same error unfortunately. – Perceptic Feb 11 '22 at 16:09
  • If you get the same error then your annotation for `createNavigationContainerRef` isn't correct. You need to share the type of `RootStackParamList` as well as the code you're using to call `navigate` – satya164 Feb 11 '22 at 18:43
  • It doesn't seem to matter what `RootStackParamList` is. It can simply be `interface RootStackParamList { Home: undefined }`. I'm not calling it anywhere yet but that wouldn't really be relevant anyway. – Perceptic Feb 11 '22 at 22:25
  • Any luck on it? – divyansh ingle Apr 01 '22 at 14:02
0

try this:

export const navigate: typeof navigationRef.navigate = (name, params?) => {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
};
I'm AI
  • 1
  • 1