Skip to content
Source
Sign inSign up

root-stack-reset.ts

44 lines1.7 KB

1import type { CommonActions, NavigationState } from "@react-navigation/native";
2​
3export type RootStackResetAction = ReturnType<typeof CommonActions.reset> & {
4 readonly target: string;
5};
6​
7export interface RootStackNavigation {
8 readonly dispatch: (action: RootStackResetAction) => void;
9 readonly getParent: () => RootStackNavigation | undefined;
10 readonly getState: () => NavigationState | undefined;
11 /** Only on the navigation container, whose `getState` stays empty until the first action. */
12 readonly getRootState?: () => NavigationState | undefined;
14​
15/**
16 * The root stack's state, read from anywhere. The sidebar and rail render in the root layout,
17 * where `useNavigation()` is the container, so walk up to the root navigator.
18 */
19export function rootStackState(navigation: RootStackNavigation) {
20 let root = navigation;
21 for (let parent = root.getParent(); parent; parent = root.getParent()) root = parent;
22 return root.getRootState?.() ?? root.getState();
24​
25/**
26 * Replaces the root stack. Targets the root explicitly: a container dispatch runs on the deepest
27 * focused navigator, which can be a nested stack that rejects the reset.
28 */
29export function dispatchRootStackReset(
30 navigation: RootStackNavigation,
31 state: NavigationState,
32 payload: RootStackResetAction["payload"],
33) {
34 // Same shape as `CommonActions.reset`, which would pull React Native into node tests.
35 navigation.dispatch({ type: "RESET", payload, target: state.key });
37​
38export function resetRootStack(
39 navigation: RootStackNavigation,
40 nextState: (state: NavigationState) => RootStackResetAction["payload"],
41) {
42 const state = rootStackState(navigation);
43 if (state) dispatchRootStackReset(navigation, state, nextState(state));