@react-navigation/core 8.0.0-alpha.0 → 8.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/lib/module/BaseNavigationContainer.js +14 -7
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/ConsumedParamsContext.js +5 -0
  4. package/lib/module/ConsumedParamsContext.js.map +1 -0
  5. package/lib/module/NavigationBuilderContext.js +1 -0
  6. package/lib/module/NavigationBuilderContext.js.map +1 -1
  7. package/lib/module/NavigationIndependentTree.js +8 -4
  8. package/lib/module/NavigationIndependentTree.js.map +1 -1
  9. package/lib/module/NavigationMetaContext.js +15 -0
  10. package/lib/module/NavigationMetaContext.js.map +1 -0
  11. package/lib/module/NavigationProvider.js +14 -3
  12. package/lib/module/NavigationProvider.js.map +1 -1
  13. package/lib/module/NavigationStateContext.js.map +1 -1
  14. package/lib/module/PreventRemoveProvider.js +3 -3
  15. package/lib/module/PreventRemoveProvider.js.map +1 -1
  16. package/lib/module/SceneView.js +46 -56
  17. package/lib/module/SceneView.js.map +1 -1
  18. package/lib/module/StaticNavigation.js +30 -4
  19. package/lib/module/StaticNavigation.js.map +1 -1
  20. package/lib/module/createNavigatorFactory.js +22 -1
  21. package/lib/module/createNavigatorFactory.js.map +1 -1
  22. package/lib/module/getPathFromState.js +25 -3
  23. package/lib/module/getPathFromState.js.map +1 -1
  24. package/lib/module/getStateFromPath.js +158 -73
  25. package/lib/module/getStateFromPath.js.map +1 -1
  26. package/lib/module/getStateFromRouteParams.js +24 -0
  27. package/lib/module/getStateFromRouteParams.js.map +1 -0
  28. package/lib/module/index.js +2 -1
  29. package/lib/module/index.js.map +1 -1
  30. package/lib/module/theming/useTheme.js +1 -1
  31. package/lib/module/theming/useTheme.js.map +1 -1
  32. package/lib/module/types.js.map +1 -1
  33. package/lib/module/useCurrentRender.js +1 -1
  34. package/lib/module/useCurrentRender.js.map +1 -1
  35. package/lib/module/useDescriptors.js +12 -43
  36. package/lib/module/useDescriptors.js.map +1 -1
  37. package/lib/module/useFocusEvents.js +1 -1
  38. package/lib/module/useFocusEvents.js.map +1 -1
  39. package/lib/module/useFocusedListenersChildrenAdapter.js +1 -1
  40. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  41. package/lib/module/useIsFocused.js +7 -12
  42. package/lib/module/useIsFocused.js.map +1 -1
  43. package/lib/module/useNavigationBuilder.js +92 -42
  44. package/lib/module/useNavigationBuilder.js.map +1 -1
  45. package/lib/module/useNavigationCache.js +14 -56
  46. package/lib/module/useNavigationCache.js.map +1 -1
  47. package/lib/module/useNavigationHelpers.js +1 -1
  48. package/lib/module/useNavigationHelpers.js.map +1 -1
  49. package/lib/module/useNavigationIndependentTree.js +1 -1
  50. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  51. package/lib/module/useNavigationState.js +4 -2
  52. package/lib/module/useNavigationState.js.map +1 -1
  53. package/lib/module/useOnAction.js +1 -1
  54. package/lib/module/useOnAction.js.map +1 -1
  55. package/lib/module/useOnGetState.js +2 -2
  56. package/lib/module/useOnGetState.js.map +1 -1
  57. package/lib/module/useOnPreventRemove.js +2 -2
  58. package/lib/module/useOnPreventRemove.js.map +1 -1
  59. package/lib/module/useOnRouteFocus.js +1 -1
  60. package/lib/module/useOnRouteFocus.js.map +1 -1
  61. package/lib/module/useOptionsGetters.js +2 -2
  62. package/lib/module/useOptionsGetters.js.map +1 -1
  63. package/lib/module/usePreventRemoveContext.js +1 -1
  64. package/lib/module/usePreventRemoveContext.js.map +1 -1
  65. package/lib/module/useRegisterNavigator.js +1 -1
  66. package/lib/module/useRegisterNavigator.js.map +1 -1
  67. package/lib/module/useScheduleUpdate.js +1 -1
  68. package/lib/module/useScheduleUpdate.js.map +1 -1
  69. package/lib/module/useStateForPath.js +1 -1
  70. package/lib/module/useStateForPath.js.map +1 -1
  71. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  72. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  73. package/lib/typescript/src/ConsumedParamsContext.d.ts +8 -0
  74. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  75. package/lib/typescript/src/NavigationBuilderContext.d.ts +11 -5
  76. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  77. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  78. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  79. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  80. package/lib/typescript/src/NavigationMetaContext.d.ts +12 -0
  81. package/lib/typescript/src/NavigationMetaContext.d.ts.map +1 -0
  82. package/lib/typescript/src/NavigationProvider.d.ts +4 -4
  83. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  84. package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
  85. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  86. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  87. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  88. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  89. package/lib/typescript/src/StaticNavigation.d.ts +33 -19
  90. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  91. package/lib/typescript/src/createNavigatorFactory.d.ts +1 -1
  92. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  93. package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
  94. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  95. package/lib/typescript/src/getActionFromState.d.ts +3 -3
  96. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  97. package/lib/typescript/src/getPathFromState.d.ts +2 -2
  98. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  99. package/lib/typescript/src/getStateFromPath.d.ts +3 -3
  100. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  101. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  102. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  103. package/lib/typescript/src/index.d.ts +3 -1
  104. package/lib/typescript/src/index.d.ts.map +1 -1
  105. package/lib/typescript/src/types.d.ts +144 -82
  106. package/lib/typescript/src/types.d.ts.map +1 -1
  107. package/lib/typescript/src/useDescriptors.d.ts +12 -25
  108. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  109. package/lib/typescript/src/useIsFocused.d.ts +3 -0
  110. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  111. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  112. package/lib/typescript/src/useNavigationBuilder.d.ts +20 -29
  113. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  114. package/lib/typescript/src/useNavigationCache.d.ts +2 -42
  115. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  116. package/lib/typescript/src/useNavigationHelpers.d.ts +18 -16
  117. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  118. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  119. package/lib/typescript/src/useOnAction.d.ts +6 -6
  120. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  121. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  122. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  123. package/lib/typescript/src/useRouteCache.d.ts +2 -2
  124. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  125. package/lib/typescript/src/utilities.d.ts +35 -3
  126. package/lib/typescript/src/utilities.d.ts.map +1 -1
  127. package/package.json +20 -18
  128. package/src/BaseNavigationContainer.tsx +332 -326
  129. package/src/ConsumedParamsContext.tsx +10 -0
  130. package/src/NavigationBuilderContext.tsx +14 -8
  131. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  132. package/src/NavigationIndependentTree.tsx +8 -5
  133. package/src/NavigationMetaContext.tsx +14 -0
  134. package/src/NavigationProvider.tsx +17 -3
  135. package/src/NavigationStateContext.tsx +5 -6
  136. package/src/PreventRemoveProvider.tsx +3 -3
  137. package/src/SceneView.tsx +58 -56
  138. package/src/StaticNavigation.tsx +100 -30
  139. package/src/createNavigatorFactory.tsx +35 -4
  140. package/src/findFocusedRoute.tsx +3 -3
  141. package/src/getActionFromState.tsx +7 -7
  142. package/src/getPathFromState.tsx +53 -9
  143. package/src/getStateFromPath.tsx +255 -97
  144. package/src/getStateFromRouteParams.tsx +60 -0
  145. package/src/index.tsx +2 -1
  146. package/src/theming/useTheme.tsx +1 -1
  147. package/src/types.tsx +330 -187
  148. package/src/useCurrentRender.tsx +1 -1
  149. package/src/useDescriptors.tsx +13 -48
  150. package/src/useFocusEvents.tsx +1 -1
  151. package/src/useFocusedListenersChildrenAdapter.tsx +1 -1
  152. package/src/useIsFocused.tsx +14 -21
  153. package/src/useNavigation.tsx +2 -2
  154. package/src/useNavigationBuilder.tsx +138 -53
  155. package/src/useNavigationCache.tsx +12 -73
  156. package/src/useNavigationHelpers.tsx +1 -1
  157. package/src/useNavigationIndependentTree.tsx +1 -1
  158. package/src/useNavigationState.tsx +6 -4
  159. package/src/useOnAction.tsx +8 -8
  160. package/src/useOnGetState.tsx +2 -2
  161. package/src/useOnPreventRemove.tsx +2 -2
  162. package/src/useOnRouteFocus.tsx +10 -12
  163. package/src/useOptionsGetters.tsx +2 -2
  164. package/src/usePreventRemoveContext.tsx +1 -1
  165. package/src/useRegisterNavigator.tsx +1 -1
  166. package/src/useScheduleUpdate.tsx +1 -3
  167. package/src/useStateForPath.tsx +1 -1
  168. package/src/utilities.tsx +72 -4
@@ -3,7 +3,6 @@ import {
3
3
  type InitialState,
4
4
  type NavigationAction,
5
5
  type NavigationState,
6
- type ParamListBase,
7
6
  type PartialState,
8
7
  type Route,
9
8
  } from '@react-navigation/routers';
@@ -24,6 +23,7 @@ import type {
24
23
  NavigationContainerEventMap,
25
24
  NavigationContainerProps,
26
25
  NavigationContainerRef,
26
+ RootParamList,
27
27
  } from './types';
28
28
  import { UnhandledActionContext } from './UnhandledActionContext';
29
29
  import { useChildListeners } from './useChildListeners';
@@ -38,6 +38,10 @@ type State = NavigationState | PartialState<NavigationState> | undefined;
38
38
  const serializableWarnings: string[] = [];
39
39
  const duplicateNameWarnings: string[] = [];
40
40
 
41
+ type Props<ParamList extends {}> = NavigationContainerProps & {
42
+ ref?: React.Ref<NavigationContainerRef<ParamList>>;
43
+ };
44
+
41
45
  /**
42
46
  * Remove `key` and `routeNames` from the state objects recursively to get partial state.
43
47
  *
@@ -80,382 +84,384 @@ const getPartialState = (
80
84
  * @param props.children Child elements to render the content.
81
85
  * @param props.ref Ref object which refers to the navigation object containing helper methods.
82
86
  */
83
- export const BaseNavigationContainer = React.forwardRef(
84
- function BaseNavigationContainer(
85
- {
86
- initialState,
87
- onStateChange,
88
- onReady,
89
- onUnhandledAction,
90
- theme,
91
- children,
92
- }: NavigationContainerProps,
93
- ref?: React.Ref<NavigationContainerRef<ParamListBase>>
94
- ) {
95
- const parent = React.useContext(NavigationStateContext);
96
- const independent = useNavigationIndependentTree();
97
-
98
- if (!parent.isDefault && !independent) {
99
- throw new Error(
100
- "Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, wrap the container in 'NavigationIndependentTree' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them."
101
- );
102
- }
87
+ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
88
+ initialState,
89
+ onStateChange,
90
+ onReady,
91
+ onUnhandledAction,
92
+ theme,
93
+ children,
94
+ ref,
95
+ }: Props<ParamList>) {
96
+ const parent = React.use(NavigationStateContext);
97
+ const independent = useNavigationIndependentTree();
98
+
99
+ if (!parent.isDefault && !independent) {
100
+ throw new Error(
101
+ "Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, wrap the container in 'NavigationIndependentTree' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them."
102
+ );
103
+ }
103
104
 
104
- const { state, getState, setState, scheduleUpdate, flushUpdates } =
105
- useSyncState<State>(() =>
106
- getPartialState(initialState == null ? undefined : initialState)
107
- );
105
+ const { state, getState, setState, scheduleUpdate, flushUpdates } =
106
+ useSyncState<State>(() =>
107
+ getPartialState(initialState == null ? undefined : initialState)
108
+ );
108
109
 
109
- const isFirstMountRef = React.useRef<boolean>(true);
110
+ const isFirstMountRef = React.useRef<boolean>(true);
110
111
 
111
- const navigatorKeyRef = React.useRef<string | undefined>(undefined);
112
+ const navigatorKeyRef = React.useRef<string | undefined>(undefined);
112
113
 
113
- const getKey = React.useCallback(() => navigatorKeyRef.current, []);
114
+ const getKey = React.useCallback(() => navigatorKeyRef.current, []);
114
115
 
115
- const setKey = React.useCallback((key: string) => {
116
- navigatorKeyRef.current = key;
117
- }, []);
116
+ const setKey = React.useCallback((key: string) => {
117
+ navigatorKeyRef.current = key;
118
+ }, []);
118
119
 
119
- const { listeners, addListener } = useChildListeners();
120
+ const { listeners, addListener } = useChildListeners();
120
121
 
121
- const { keyedListeners, addKeyedListener } = useKeyedChildListeners();
122
+ const { keyedListeners, addKeyedListener } = useKeyedChildListeners();
122
123
 
123
- const dispatch = useLatestCallback(
124
- (
125
- action:
126
- | NavigationAction
127
- | ((state: NavigationState) => NavigationAction)
128
- ) => {
129
- if (listeners.focus[0] == null) {
130
- console.error(NOT_INITIALIZED_ERROR);
131
- } else {
132
- listeners.focus[0]((navigation) => navigation.dispatch(action));
133
- }
124
+ const dispatch = useLatestCallback(
125
+ (
126
+ action: NavigationAction | ((state: NavigationState) => NavigationAction)
127
+ ) => {
128
+ if (listeners.focus[0] == null) {
129
+ console.error(NOT_INITIALIZED_ERROR);
130
+ } else {
131
+ listeners.focus[0]((navigation) => navigation.dispatch(action));
134
132
  }
133
+ }
134
+ );
135
+
136
+ const canGoBack = useLatestCallback(() => {
137
+ if (listeners.focus[0] == null) {
138
+ return false;
139
+ }
140
+
141
+ const { result, handled } = listeners.focus[0]((navigation) =>
142
+ navigation.canGoBack()
135
143
  );
136
144
 
137
- const canGoBack = useLatestCallback(() => {
138
- if (listeners.focus[0] == null) {
139
- return false;
140
- }
145
+ if (handled) {
146
+ return result;
147
+ } else {
148
+ return false;
149
+ }
150
+ });
141
151
 
142
- const { result, handled } = listeners.focus[0]((navigation) =>
143
- navigation.canGoBack()
144
- );
152
+ const resetRoot = useLatestCallback(
153
+ (state: PartialState<NavigationState> | NavigationState) => {
154
+ const target = state?.key ?? keyedListeners.getState.root?.().key;
145
155
 
146
- if (handled) {
147
- return result;
156
+ if (target == null) {
157
+ console.error(NOT_INITIALIZED_ERROR);
148
158
  } else {
149
- return false;
159
+ listeners.focus[0]((navigation) =>
160
+ navigation.dispatch({
161
+ ...CommonActions.reset(state),
162
+ target,
163
+ })
164
+ );
150
165
  }
151
- });
166
+ }
167
+ );
152
168
 
153
- const resetRoot = useLatestCallback(
154
- (state?: PartialState<NavigationState> | NavigationState) => {
155
- const target = state?.key ?? keyedListeners.getState.root?.().key;
156
-
157
- if (target == null) {
158
- console.error(NOT_INITIALIZED_ERROR);
159
- } else {
160
- listeners.focus[0]((navigation) =>
161
- navigation.dispatch({
162
- ...CommonActions.reset(state),
163
- target,
164
- })
165
- );
166
- }
167
- }
168
- );
169
+ const getRootState = useLatestCallback(() => {
170
+ return keyedListeners.getState.root?.();
171
+ });
169
172
 
170
- const getRootState = useLatestCallback(() => {
171
- return keyedListeners.getState.root?.();
172
- });
173
+ const getCurrentRoute = useLatestCallback(() => {
174
+ const state = getRootState();
173
175
 
174
- const getCurrentRoute = useLatestCallback(() => {
175
- const state = getRootState();
176
+ if (state == null) {
177
+ return undefined;
178
+ }
176
179
 
177
- if (state == null) {
178
- return undefined;
179
- }
180
+ const route = findFocusedRoute(state);
181
+
182
+ return route as Route<string> | undefined;
183
+ });
184
+
185
+ const isReady = useLatestCallback(() => listeners.focus[0] != null);
186
+
187
+ const emitter = useEventEmitter<NavigationContainerEventMap>();
188
+
189
+ const { addOptionsGetter, getCurrentOptions } = useOptionsGetters({});
190
+
191
+ const navigation: NavigationContainerRef<ParamList> = React.useMemo(
192
+ () => ({
193
+ ...Object.keys(CommonActions).reduce<any>((acc, name) => {
194
+ acc[name] = (...args: any[]) =>
195
+ // @ts-expect-error: this is ok
196
+ dispatch(CommonActions[name](...args));
197
+ return acc;
198
+ }, {}),
199
+ ...emitter.create('root'),
200
+ dispatch,
201
+ resetRoot,
202
+ isFocused: () => true,
203
+ canGoBack,
204
+ getParent: () => undefined,
205
+ getState,
206
+ getRootState,
207
+ getCurrentRoute,
208
+ getCurrentOptions,
209
+ isReady,
210
+ setOptions: () => {
211
+ throw new Error('Cannot call setOptions outside a screen');
212
+ },
213
+ }),
214
+ [
215
+ canGoBack,
216
+ dispatch,
217
+ emitter,
218
+ getCurrentOptions,
219
+ getCurrentRoute,
220
+ getRootState,
221
+ getState,
222
+ isReady,
223
+ resetRoot,
224
+ ]
225
+ );
226
+
227
+ React.useImperativeHandle(ref, () => navigation, [navigation]);
228
+
229
+ const onDispatchAction = useLatestCallback(
230
+ (action: NavigationAction, noop: boolean) => {
231
+ emitter.emit({
232
+ type: '__unsafe_action__',
233
+ data: { action, noop, stack: stackRef.current },
234
+ });
235
+ }
236
+ );
237
+
238
+ const onEmitEvent = useLatestCallback(
239
+ (event: {
240
+ type: string;
241
+ defaultPrevented: boolean | undefined;
242
+ target: string | undefined;
243
+ data: unknown;
244
+ }) => {
245
+ emitter.emit({
246
+ type: '__unsafe_event__',
247
+ data: event,
248
+ });
249
+ }
250
+ );
180
251
 
181
- const route = findFocusedRoute(state);
252
+ const lastEmittedOptionsRef = React.useRef<object | undefined>(undefined);
182
253
 
183
- return route as Route<string> | undefined;
184
- });
254
+ const onOptionsChange = useLatestCallback((options: object) => {
255
+ if (lastEmittedOptionsRef.current === options) {
256
+ return;
257
+ }
185
258
 
186
- const isReady = useLatestCallback(() => listeners.focus[0] != null);
187
-
188
- const emitter = useEventEmitter<NavigationContainerEventMap>();
189
-
190
- const { addOptionsGetter, getCurrentOptions } = useOptionsGetters({});
191
-
192
- const navigation: NavigationContainerRef<ParamListBase> = React.useMemo(
193
- () => ({
194
- ...Object.keys(CommonActions).reduce<any>((acc, name) => {
195
- acc[name] = (...args: any[]) =>
196
- // @ts-expect-error: this is ok
197
- dispatch(CommonActions[name](...args));
198
- return acc;
199
- }, {}),
200
- ...emitter.create('root'),
201
- dispatch,
202
- resetRoot,
203
- isFocused: () => true,
204
- canGoBack,
205
- getParent: () => undefined,
206
- getState,
207
- getRootState,
208
- getCurrentRoute,
209
- getCurrentOptions,
210
- isReady,
211
- setOptions: () => {
212
- throw new Error('Cannot call setOptions outside a screen');
213
- },
214
- }),
215
- [
216
- canGoBack,
217
- dispatch,
218
- emitter,
219
- getCurrentOptions,
220
- getCurrentRoute,
221
- getRootState,
222
- getState,
223
- isReady,
224
- resetRoot,
225
- ]
226
- );
259
+ lastEmittedOptionsRef.current = options;
227
260
 
228
- React.useImperativeHandle(ref, () => navigation, [navigation]);
261
+ emitter.emit({
262
+ type: 'options',
263
+ data: { options },
264
+ });
265
+ });
266
+
267
+ const stackRef = React.useRef<string | undefined>(undefined);
268
+
269
+ const builderContext = React.useMemo(
270
+ () => ({
271
+ addListener,
272
+ addKeyedListener,
273
+ onDispatchAction,
274
+ onEmitEvent,
275
+ onOptionsChange,
276
+ scheduleUpdate,
277
+ flushUpdates,
278
+ stackRef,
279
+ }),
280
+ [
281
+ addListener,
282
+ addKeyedListener,
283
+ onDispatchAction,
284
+ onEmitEvent,
285
+ onOptionsChange,
286
+ scheduleUpdate,
287
+ flushUpdates,
288
+ ]
289
+ );
290
+
291
+ const isInitialRef = React.useRef(true);
292
+
293
+ const getIsInitial = React.useCallback(() => isInitialRef.current, []);
294
+
295
+ const context = React.useMemo(
296
+ () => ({
297
+ state,
298
+ getState,
299
+ setState,
300
+ getKey,
301
+ setKey,
302
+ getIsInitial,
303
+ addOptionsGetter,
304
+ }),
305
+ [state, getState, setState, getKey, setKey, getIsInitial, addOptionsGetter]
306
+ );
229
307
 
230
- const onDispatchAction = useLatestCallback(
231
- (action: NavigationAction, noop: boolean) => {
232
- emitter.emit({
233
- type: '__unsafe_action__',
234
- data: { action, noop, stack: stackRef.current },
235
- });
236
- }
237
- );
308
+ const onReadyRef = React.useRef(onReady);
309
+ const onStateChangeRef = React.useRef(onStateChange);
238
310
 
239
- const lastEmittedOptionsRef = React.useRef<object | undefined>(undefined);
311
+ React.useEffect(() => {
312
+ isInitialRef.current = false;
313
+ onStateChangeRef.current = onStateChange;
314
+ onReadyRef.current = onReady;
315
+ });
240
316
 
241
- const onOptionsChange = useLatestCallback((options: object) => {
242
- if (lastEmittedOptionsRef.current === options) {
243
- return;
244
- }
317
+ const onReadyCalledRef = React.useRef(false);
245
318
 
246
- lastEmittedOptionsRef.current = options;
319
+ React.useEffect(() => {
320
+ if (!onReadyCalledRef.current && isReady()) {
321
+ onReadyCalledRef.current = true;
322
+ onReadyRef.current?.();
323
+ emitter.emit({ type: 'ready' });
324
+ }
325
+ }, [state, isReady, emitter]);
247
326
 
248
- emitter.emit({
249
- type: 'options',
250
- data: { options },
251
- });
252
- });
327
+ React.useEffect(() => {
328
+ const hydratedState = getRootState();
253
329
 
254
- const stackRef = React.useRef<string | undefined>(undefined);
255
-
256
- const builderContext = React.useMemo(
257
- () => ({
258
- addListener,
259
- addKeyedListener,
260
- onDispatchAction,
261
- onOptionsChange,
262
- scheduleUpdate,
263
- flushUpdates,
264
- stackRef,
265
- }),
266
- [
267
- addListener,
268
- addKeyedListener,
269
- onDispatchAction,
270
- onOptionsChange,
271
- scheduleUpdate,
272
- flushUpdates,
273
- ]
274
- );
330
+ if (process.env.NODE_ENV !== 'production') {
331
+ if (hydratedState !== undefined) {
332
+ const serializableResult = checkSerializable(hydratedState);
275
333
 
276
- const isInitialRef = React.useRef(true);
277
-
278
- const getIsInitial = React.useCallback(() => isInitialRef.current, []);
279
-
280
- const context = React.useMemo(
281
- () => ({
282
- state,
283
- getState,
284
- setState,
285
- getKey,
286
- setKey,
287
- getIsInitial,
288
- addOptionsGetter,
289
- }),
290
- [
291
- state,
292
- getState,
293
- setState,
294
- getKey,
295
- setKey,
296
- getIsInitial,
297
- addOptionsGetter,
298
- ]
299
- );
334
+ if (!serializableResult.serializable) {
335
+ const { location, reason } = serializableResult;
300
336
 
301
- const onReadyRef = React.useRef(onReady);
302
- const onStateChangeRef = React.useRef(onStateChange);
337
+ let path = '';
338
+ let pointer: Record<any, any> = hydratedState;
339
+ let params = false;
303
340
 
304
- React.useEffect(() => {
305
- isInitialRef.current = false;
306
- onStateChangeRef.current = onStateChange;
307
- onReadyRef.current = onReady;
308
- });
341
+ for (let i = 0; i < location.length; i++) {
342
+ const curr = location[i];
343
+ const prev = location[i - 1];
309
344
 
310
- const onReadyCalledRef = React.useRef(false);
345
+ pointer = pointer[curr];
311
346
 
312
- React.useEffect(() => {
313
- if (!onReadyCalledRef.current && isReady()) {
314
- onReadyCalledRef.current = true;
315
- onReadyRef.current?.();
316
- emitter.emit({ type: 'ready' });
317
- }
318
- }, [state, isReady, emitter]);
319
-
320
- React.useEffect(() => {
321
- const hydratedState = getRootState();
322
-
323
- if (process.env.NODE_ENV !== 'production') {
324
- if (hydratedState !== undefined) {
325
- const serializableResult = checkSerializable(hydratedState);
326
-
327
- if (!serializableResult.serializable) {
328
- const { location, reason } = serializableResult;
329
-
330
- let path = '';
331
- let pointer: Record<any, any> = hydratedState;
332
- let params = false;
333
-
334
- for (let i = 0; i < location.length; i++) {
335
- const curr = location[i];
336
- const prev = location[i - 1];
337
-
338
- pointer = pointer[curr];
339
-
340
- if (!params && curr === 'state') {
341
- continue;
342
- } else if (!params && curr === 'routes') {
343
- if (path) {
344
- path += ' > ';
345
- }
346
- } else if (
347
- !params &&
348
- typeof curr === 'number' &&
349
- prev === 'routes'
350
- ) {
351
- path += pointer?.name;
352
- } else if (!params) {
353
- path += ` > ${curr}`;
354
- params = true;
347
+ if (!params && curr === 'state') {
348
+ continue;
349
+ } else if (!params && curr === 'routes') {
350
+ if (path) {
351
+ path += ' > ';
352
+ }
353
+ } else if (
354
+ !params &&
355
+ typeof curr === 'number' &&
356
+ prev === 'routes'
357
+ ) {
358
+ path += pointer?.name;
359
+ } else if (!params) {
360
+ path += ` > ${curr}`;
361
+ params = true;
362
+ } else {
363
+ if (typeof curr === 'number' || /^[0-9]+$/.test(curr)) {
364
+ path += `[${curr}]`;
365
+ } else if (/^[a-z$_]+$/i.test(curr)) {
366
+ path += `.${curr}`;
355
367
  } else {
356
- if (typeof curr === 'number' || /^[0-9]+$/.test(curr)) {
357
- path += `[${curr}]`;
358
- } else if (/^[a-z$_]+$/i.test(curr)) {
359
- path += `.${curr}`;
360
- } else {
361
- path += `[${JSON.stringify(curr)}]`;
362
- }
368
+ path += `[${JSON.stringify(curr)}]`;
363
369
  }
364
370
  }
371
+ }
365
372
 
366
- const message = `Non-serializable values were found in the navigation state. Check:\n\n${path} (${reason})\n\nThis can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.`;
373
+ const message = `Non-serializable values were found in the navigation state. Check:\n\n${path} (${reason})\n\nThis can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.`;
367
374
 
368
- if (!serializableWarnings.includes(message)) {
369
- serializableWarnings.push(message);
370
- console.warn(message);
371
- }
375
+ if (!serializableWarnings.includes(message)) {
376
+ serializableWarnings.push(message);
377
+ console.warn(message);
372
378
  }
379
+ }
373
380
 
374
- const duplicateRouteNamesResult =
375
- checkDuplicateRouteNames(hydratedState);
381
+ const duplicateRouteNamesResult =
382
+ checkDuplicateRouteNames(hydratedState);
376
383
 
377
- if (duplicateRouteNamesResult.length) {
378
- const message = `Found screens with the same name nested inside one another. Check:\n${duplicateRouteNamesResult.map(
379
- (locations) => `\n${locations.join(', ')}`
380
- )}\n\nThis can cause confusing behavior during navigation. Consider using unique names for each screen instead.`;
384
+ if (duplicateRouteNamesResult.length) {
385
+ const message = `Found screens with the same name nested inside one another. Check:\n${duplicateRouteNamesResult.map(
386
+ (locations) => `\n${locations.join(', ')}`
387
+ )}\n\nThis can cause confusing behavior during navigation. Consider using unique names for each screen instead.`;
381
388
 
382
- if (!duplicateNameWarnings.includes(message)) {
383
- duplicateNameWarnings.push(message);
384
- console.warn(message);
385
- }
389
+ if (!duplicateNameWarnings.includes(message)) {
390
+ duplicateNameWarnings.push(message);
391
+ console.warn(message);
386
392
  }
387
393
  }
388
394
  }
395
+ }
389
396
 
390
- emitter.emit({ type: 'state', data: { state } });
391
-
392
- if (!isFirstMountRef.current && onStateChangeRef.current) {
393
- onStateChangeRef.current(hydratedState);
394
- }
395
-
396
- isFirstMountRef.current = false;
397
- }, [getRootState, emitter, state]);
397
+ emitter.emit({ type: 'state', data: { state } });
398
398
 
399
- const defaultOnUnhandledAction = useLatestCallback(
400
- (action: NavigationAction) => {
401
- if (process.env.NODE_ENV === 'production') {
402
- return;
403
- }
399
+ if (!isFirstMountRef.current && onStateChangeRef.current) {
400
+ onStateChangeRef.current(hydratedState);
401
+ }
404
402
 
405
- const payload: Record<string, any> | undefined = action.payload;
406
-
407
- let message = `The action '${action.type}'${
408
- payload ? ` with payload ${JSON.stringify(action.payload)}` : ''
409
- } was not handled by any navigator.`;
410
-
411
- switch (action.type) {
412
- case 'PRELOAD':
413
- case 'NAVIGATE':
414
- case 'PUSH':
415
- case 'REPLACE':
416
- case 'POP_TO':
417
- case 'JUMP_TO':
418
- if (payload?.name) {
419
- message += `\n\nDo you have a screen named '${payload.name}'?\n\nIf you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.\n\nIf you're using conditional rendering, navigation will happen automatically and you shouldn't navigate manually, see.`;
420
- } else {
421
- message += `\n\nYou need to pass the name of the screen to navigate to.\n\nSee https://reactnavigation.org/docs/navigation-actions for usage.`;
422
- }
403
+ isFirstMountRef.current = false;
404
+ }, [getRootState, emitter, state]);
423
405
 
424
- break;
425
- case 'GO_BACK':
426
- case 'POP':
427
- case 'POP_TO_TOP':
428
- message += `\n\nIs there any screen to go back to?`;
429
- break;
430
- case 'OPEN_DRAWER':
431
- case 'CLOSE_DRAWER':
432
- case 'TOGGLE_DRAWER':
433
- message += `\n\nIs your screen inside a Drawer navigator?`;
434
- break;
435
- }
406
+ const defaultOnUnhandledAction = useLatestCallback(
407
+ (action: NavigationAction) => {
408
+ if (process.env.NODE_ENV === 'production') {
409
+ return;
410
+ }
436
411
 
437
- message += `\n\nThis is a development-only warning and won't be shown in production.`;
412
+ const payload: Record<string, any> | undefined = action.payload;
413
+
414
+ let message = `The action '${action.type}'${
415
+ payload ? ` with payload ${JSON.stringify(action.payload)}` : ''
416
+ } was not handled by any navigator.`;
417
+
418
+ switch (action.type) {
419
+ case 'PRELOAD':
420
+ case 'NAVIGATE':
421
+ case 'PUSH':
422
+ case 'REPLACE':
423
+ case 'POP_TO':
424
+ case 'JUMP_TO':
425
+ if (payload?.name) {
426
+ message += `\n\nDo you have a screen named '${payload.name}'?\n\nIf you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.\n\nIf you're using conditional rendering, navigation will happen automatically and you shouldn't navigate manually, see.`;
427
+ } else {
428
+ message += `\n\nYou need to pass the name of the screen to navigate to.\n\nSee https://reactnavigation.org/docs/navigation-actions for usage.`;
429
+ }
438
430
 
439
- console.error(message);
431
+ break;
432
+ case 'GO_BACK':
433
+ case 'POP':
434
+ case 'POP_TO_TOP':
435
+ message += `\n\nIs there any screen to go back to?`;
436
+ break;
437
+ case 'OPEN_DRAWER':
438
+ case 'CLOSE_DRAWER':
439
+ case 'TOGGLE_DRAWER':
440
+ message += `\n\nIs your screen inside a Drawer navigator?`;
441
+ break;
440
442
  }
441
- );
442
443
 
443
- return (
444
- <NavigationIndependentTreeContext.Provider value={false}>
445
- <NavigationContainerRefContext.Provider value={navigation}>
446
- <NavigationBuilderContext.Provider value={builderContext}>
447
- <NavigationStateContext.Provider value={context}>
448
- <UnhandledActionContext.Provider
449
- value={onUnhandledAction ?? defaultOnUnhandledAction}
450
- >
451
- <EnsureSingleNavigator>
452
- <ThemeProvider value={theme}>{children}</ThemeProvider>
453
- </EnsureSingleNavigator>
454
- </UnhandledActionContext.Provider>
455
- </NavigationStateContext.Provider>
456
- </NavigationBuilderContext.Provider>
457
- </NavigationContainerRefContext.Provider>
458
- </NavigationIndependentTreeContext.Provider>
459
- );
460
- }
461
- );
444
+ message += `\n\nThis is a development-only warning and won't be shown in production.`;
445
+
446
+ console.error(message);
447
+ }
448
+ );
449
+
450
+ return (
451
+ <NavigationIndependentTreeContext.Provider value={false}>
452
+ <NavigationContainerRefContext.Provider value={navigation}>
453
+ <NavigationBuilderContext.Provider value={builderContext}>
454
+ <NavigationStateContext.Provider value={context}>
455
+ <UnhandledActionContext.Provider
456
+ value={onUnhandledAction ?? defaultOnUnhandledAction}
457
+ >
458
+ <EnsureSingleNavigator>
459
+ <ThemeProvider value={theme}>{children}</ThemeProvider>
460
+ </EnsureSingleNavigator>
461
+ </UnhandledActionContext.Provider>
462
+ </NavigationStateContext.Provider>
463
+ </NavigationBuilderContext.Provider>
464
+ </NavigationContainerRefContext.Provider>
465
+ </NavigationIndependentTreeContext.Provider>
466
+ );
467
+ }