UNPKG

3.25 kBTypeScriptView Raw
1import {
2 CommonActions,
3 NavigationAction,
4 NavigationState,
5 ParamListBase,
6 Router,
7} from '@react-navigation/routers';
8import * as React from 'react';
9
10import NavigationContext from './NavigationContext';
11import { NavigationHelpers, PrivateValueStore } from './types';
12import UnhandledActionContext from './UnhandledActionContext';
13import type { NavigationEventEmitter } from './useEventEmitter';
14
15// This is to make TypeScript compiler happy
16// eslint-disable-next-line babel/no-unused-expressions
17PrivateValueStore;
18
19type Options<State extends NavigationState, Action extends NavigationAction> = {
20 id: string | undefined;
21 onAction: (action: NavigationAction) => boolean;
22 getState: () => State;
23 emitter: NavigationEventEmitter<any>;
24 router: Router<State, Action>;
25};
26
27/**
28 * Navigation object with helper methods to be used by a navigator.
29 * This object includes methods for common actions as well as methods the parent screen's navigation object.
30 */
31export default function useNavigationHelpers<
32 State extends NavigationState,
33 ActionHelpers extends Record<string, () => void>,
34 Action extends NavigationAction,
35 EventMap extends Record<string, any>
36>({
37 id: navigatorId,
38 onAction,
39 getState,
40 emitter,
41 router,
42}: Options<State, Action>) {
43 const onUnhandledAction = React.useContext(UnhandledActionContext);
44 const parentNavigationHelpers = React.useContext(NavigationContext);
45
46 return React.useMemo(() => {
47 const dispatch = (op: Action | ((state: State) => Action)) => {
48 const action = typeof op === 'function' ? op(getState()) : op;
49
50 const handled = onAction(action);
51
52 if (!handled) {
53 onUnhandledAction?.(action);
54 }
55 };
56
57 const actions = {
58 ...router.actionCreators,
59 ...CommonActions,
60 };
61
62 const helpers = Object.keys(actions).reduce((acc, name) => {
63 // @ts-expect-error: name is a valid key, but TypeScript is dumb
64 acc[name] = (...args: any) => dispatch(actions[name](...args));
65 return acc;
66 }, {} as ActionHelpers);
67
68 const navigationHelpers = {
69 ...parentNavigationHelpers,
70 ...helpers,
71 dispatch,
72 emit: emitter.emit,
73 isFocused: parentNavigationHelpers
74 ? parentNavigationHelpers.isFocused
75 : () => true,
76 canGoBack: () => {
77 const state = getState();
78
79 return (
80 router.getStateForAction(state, CommonActions.goBack() as Action, {
81 routeNames: state.routeNames,
82 routeParamList: {},
83 routeGetIdList: {},
84 }) !== null ||
85 parentNavigationHelpers?.canGoBack() ||
86 false
87 );
88 },
89 getId: () => navigatorId,
90 getParent: (id?: string) => {
91 if (id !== undefined) {
92 let current = navigationHelpers;
93
94 while (current && id !== current.getId()) {
95 current = current.getParent();
96 }
97
98 return current;
99 }
100
101 return parentNavigationHelpers;
102 },
103 getState,
104 } as NavigationHelpers<ParamListBase, EventMap> & ActionHelpers;
105
106 return navigationHelpers;
107 }, [
108 navigatorId,
109 emitter.emit,
110 getState,
111 onAction,
112 onUnhandledAction,
113 parentNavigationHelpers,
114 router,
115 ]);
116}