1 | import type {
|
2 | NavigationAction,
|
3 | NavigationState,
|
4 | PartialState,
|
5 | Router,
|
6 | RouterConfigOptions,
|
7 | } from '@react-navigation/routers';
|
8 | import * as React from 'react';
|
9 |
|
10 | import NavigationBuilderContext, {
|
11 | ChildActionListener,
|
12 | ChildBeforeRemoveListener,
|
13 | } from './NavigationBuilderContext';
|
14 | import type { EventMapCore } from './types';
|
15 | import type { NavigationEventEmitter } from './useEventEmitter';
|
16 | import useOnPreventRemove, { shouldPreventRemove } from './useOnPreventRemove';
|
17 |
|
18 | type Options = {
|
19 | router: Router<NavigationState, NavigationAction>;
|
20 | key?: string;
|
21 | getState: () => NavigationState;
|
22 | setState: (state: NavigationState | PartialState<NavigationState>) => void;
|
23 | actionListeners: ChildActionListener[];
|
24 | beforeRemoveListeners: Record<string, ChildBeforeRemoveListener | undefined>;
|
25 | routerConfigOptions: RouterConfigOptions;
|
26 | emitter: NavigationEventEmitter<EventMapCore<any>>;
|
27 | };
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | export default function useOnAction({
|
39 | router,
|
40 | getState,
|
41 | setState,
|
42 | key,
|
43 | actionListeners,
|
44 | beforeRemoveListeners,
|
45 | routerConfigOptions,
|
46 | emitter,
|
47 | }: Options) {
|
48 | const {
|
49 | onAction: onActionParent,
|
50 | onRouteFocus: onRouteFocusParent,
|
51 | addListener: addListenerParent,
|
52 | onDispatchAction,
|
53 | } = React.useContext(NavigationBuilderContext);
|
54 |
|
55 | const routerConfigOptionsRef =
|
56 | React.useRef<RouterConfigOptions>(routerConfigOptions);
|
57 |
|
58 | React.useEffect(() => {
|
59 | routerConfigOptionsRef.current = routerConfigOptions;
|
60 | });
|
61 |
|
62 | const onAction = React.useCallback(
|
63 | (
|
64 | action: NavigationAction,
|
65 | visitedNavigators: Set<string> = new Set<string>()
|
66 | ) => {
|
67 | const state = getState();
|
68 |
|
69 |
|
70 |
|
71 | if (visitedNavigators.has(state.key)) {
|
72 | return false;
|
73 | }
|
74 |
|
75 | visitedNavigators.add(state.key);
|
76 |
|
77 | if (typeof action.target !== 'string' || action.target === state.key) {
|
78 | let result = router.getStateForAction(
|
79 | state,
|
80 | action,
|
81 | routerConfigOptionsRef.current
|
82 | );
|
83 |
|
84 |
|
85 |
|
86 | result =
|
87 | result === null && action.target === state.key ? state : result;
|
88 |
|
89 | if (result !== null) {
|
90 | onDispatchAction(action, state === result);
|
91 |
|
92 | if (state !== result) {
|
93 | const isPrevented = shouldPreventRemove(
|
94 | emitter,
|
95 | beforeRemoveListeners,
|
96 | state.routes,
|
97 | result.routes,
|
98 | action
|
99 | );
|
100 |
|
101 | if (isPrevented) {
|
102 | return true;
|
103 | }
|
104 |
|
105 | setState(result);
|
106 | }
|
107 |
|
108 | if (onRouteFocusParent !== undefined) {
|
109 |
|
110 |
|
111 | const shouldFocus = router.shouldActionChangeFocus(action);
|
112 |
|
113 | if (shouldFocus && key !== undefined) {
|
114 | onRouteFocusParent(key);
|
115 | }
|
116 | }
|
117 |
|
118 | return true;
|
119 | }
|
120 | }
|
121 |
|
122 | if (onActionParent !== undefined) {
|
123 |
|
124 | if (onActionParent(action, visitedNavigators)) {
|
125 | return true;
|
126 | }
|
127 | }
|
128 |
|
129 |
|
130 | for (let i = actionListeners.length - 1; i >= 0; i--) {
|
131 | const listener = actionListeners[i];
|
132 |
|
133 | if (listener(action, visitedNavigators)) {
|
134 | return true;
|
135 | }
|
136 | }
|
137 |
|
138 | return false;
|
139 | },
|
140 | [
|
141 | actionListeners,
|
142 | beforeRemoveListeners,
|
143 | emitter,
|
144 | getState,
|
145 | key,
|
146 | onActionParent,
|
147 | onDispatchAction,
|
148 | onRouteFocusParent,
|
149 | router,
|
150 | setState,
|
151 | ]
|
152 | );
|
153 |
|
154 | useOnPreventRemove({
|
155 | getState,
|
156 | emitter,
|
157 | beforeRemoveListeners,
|
158 | });
|
159 |
|
160 | React.useEffect(
|
161 | () => addListenerParent?.('action', onAction),
|
162 | [addListenerParent, onAction]
|
163 | );
|
164 |
|
165 | return onAction;
|
166 | }
|