@react-navigation/core 8.0.0-alpha.30 → 8.0.0-alpha.32
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.
- package/lib/module/BaseNavigationContainer.js +132 -82
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/DataLoading.js +3 -1
- package/lib/module/DataLoading.js.map +1 -1
- package/lib/module/NavigationBuilderContext.js +2 -1
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +21 -11
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +10 -1
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationRootContext.js +8 -0
- package/lib/module/NavigationRootContext.js.map +1 -0
- package/lib/module/NavigationStateContext.js +3 -0
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/SceneView.js +3 -1
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +54 -19
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/createNavigationContainerRef.js +1 -1
- package/lib/module/createNavigationContainerRef.js.map +1 -1
- package/lib/module/findFocusedRoute.js.map +1 -1
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +15 -16
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +0 -1
- package/lib/module/getStateFromRouteParams.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +2 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/module/types.js +0 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +6 -4
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +1 -0
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useNavigation.js +2 -2
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +14 -4
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +23 -31
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +18 -37
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationState.js +85 -33
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnGetNavigation.js +26 -0
- package/lib/module/useOnGetNavigation.js.map +1 -0
- package/lib/module/useSyncState.js +25 -6
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/DataLoading.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +4 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +9 -5
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
- package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationStateContext.d.ts +1 -0
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +2 -1
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
- package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +1 -4
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal.d.ts +3 -0
- package/lib/typescript/src/internal.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +3 -6
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +2 -1
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts +1 -0
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +1 -2
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +7 -2
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnGetNavigation.d.ts +12 -0
- package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
- package/lib/typescript/src/useSyncState.d.ts +1 -0
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/package.json +11 -5
- package/src/BaseNavigationContainer.tsx +194 -97
- package/src/DataLoading.tsx +4 -1
- package/src/NavigationBuilderContext.tsx +10 -1
- package/src/NavigationIndependentTree.tsx +27 -16
- package/src/NavigationProvider.tsx +13 -6
- package/src/NavigationRootContext.tsx +11 -0
- package/src/NavigationStateContext.tsx +4 -0
- package/src/SceneView.tsx +4 -0
- package/src/StaticNavigation.tsx +77 -19
- package/src/createNavigationContainerRef.tsx +0 -2
- package/src/findFocusedRoute.tsx +7 -12
- package/src/getActionFromState.tsx +2 -1
- package/src/getStateFromPath.tsx +31 -43
- package/src/getStateFromRouteParams.tsx +0 -1
- package/src/index.tsx +1 -0
- package/src/internal.tsx +2 -0
- package/src/types.tsx +3 -7
- package/src/useDescriptors.tsx +6 -3
- package/src/useKeyedChildListeners.tsx +1 -0
- package/src/useNavigation.tsx +2 -2
- package/src/useNavigationBuilder.tsx +14 -4
- package/src/useNavigationCache.tsx +24 -33
- package/src/useNavigationHelpers.tsx +19 -38
- package/src/useNavigationState.tsx +104 -31
- package/src/useOnGetNavigation.tsx +29 -0
- package/src/useSyncState.tsx +27 -6
- package/lib/module/checkSerializable.js +0 -51
- package/lib/module/checkSerializable.js.map +0 -1
- package/lib/typescript/src/checkSerializable.d.ts +0 -14
- package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
- package/src/checkSerializable.tsx +0 -90
|
@@ -3,24 +3,31 @@ import {
|
|
|
3
3
|
type InitialState,
|
|
4
4
|
type NavigationAction,
|
|
5
5
|
type NavigationState,
|
|
6
|
+
type ParamListBase,
|
|
6
7
|
type PartialState,
|
|
7
8
|
type Route,
|
|
8
9
|
} from '@react-navigation/routers';
|
|
9
10
|
import * as React from 'react';
|
|
10
11
|
import useLatestCallback from 'use-latest-callback';
|
|
12
|
+
import warnOnce from 'warn-once';
|
|
11
13
|
|
|
12
14
|
import { checkDuplicateRouteNames } from './checkDuplicateRouteNames';
|
|
13
|
-
import { checkSerializable } from './checkSerializable';
|
|
14
15
|
import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
15
16
|
import { NOT_INITIALIZED_ERROR } from './createNavigationContainerRef';
|
|
16
17
|
import { EnsureSingleNavigator } from './EnsureSingleNavigator';
|
|
17
18
|
import { findFocusedRoute } from './findFocusedRoute';
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
NavigationBuilderContext,
|
|
21
|
+
type WithStackTrace,
|
|
22
|
+
} from './NavigationBuilderContext';
|
|
19
23
|
import { NavigationContainerRefContext } from './NavigationContainerRefContext';
|
|
20
24
|
import { NavigationIndependentTreeContext } from './NavigationIndependentTreeContext';
|
|
25
|
+
import { NavigationRootContext } from './NavigationRootContext';
|
|
21
26
|
import { NavigationStateContext } from './NavigationStateContext';
|
|
22
27
|
import { ThemeProvider } from './theming/ThemeProvider';
|
|
23
28
|
import type {
|
|
29
|
+
EventListenerCallback,
|
|
30
|
+
GenericNavigation,
|
|
24
31
|
NavigationContainerEventMap,
|
|
25
32
|
NavigationContainerProps,
|
|
26
33
|
NavigationContainerRef,
|
|
@@ -37,9 +44,6 @@ import { useSyncState } from './useSyncState';
|
|
|
37
44
|
|
|
38
45
|
type State = NavigationState | PartialState<NavigationState> | undefined;
|
|
39
46
|
|
|
40
|
-
const serializableWarnings: string[] = [];
|
|
41
|
-
const duplicateNameWarnings: string[] = [];
|
|
42
|
-
|
|
43
47
|
type Props<ParamList extends {}> = NavigationContainerProps & {
|
|
44
48
|
ref?: React.Ref<NavigationContainerRef<ParamList>>;
|
|
45
49
|
};
|
|
@@ -104,7 +108,7 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
104
108
|
);
|
|
105
109
|
}
|
|
106
110
|
|
|
107
|
-
const { state, getState, setState, scheduleUpdate, flushUpdates } =
|
|
111
|
+
const { state, getState, setState, subscribe, scheduleUpdate, flushUpdates } =
|
|
108
112
|
useSyncState<State>(() =>
|
|
109
113
|
getPartialState(initialState == null ? undefined : initialState)
|
|
110
114
|
);
|
|
@@ -125,6 +129,41 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
125
129
|
|
|
126
130
|
const { keyedListeners, addKeyedListener } = useKeyedChildListeners();
|
|
127
131
|
|
|
132
|
+
const stackRef = React.useRef<string | undefined>(undefined);
|
|
133
|
+
|
|
134
|
+
const withStackTrace = React.useCallback<WithStackTrace>(
|
|
135
|
+
(entry, callback) => {
|
|
136
|
+
if (process.env.NODE_ENV === 'production' || stackRef.current != null) {
|
|
137
|
+
callback();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const error = new Error();
|
|
142
|
+
|
|
143
|
+
if (Error.captureStackTrace) {
|
|
144
|
+
// Available on V8 and Hermes, omits the frames of `entry` and what it called
|
|
145
|
+
Error.captureStackTrace(error, entry);
|
|
146
|
+
|
|
147
|
+
stackRef.current = error.stack;
|
|
148
|
+
} else {
|
|
149
|
+
// Other engines always include them, so we drop the frames up to `entry` ourselves
|
|
150
|
+
const frames = error.stack?.split('\n') ?? [];
|
|
151
|
+
const index = frames.findIndex((frame) =>
|
|
152
|
+
frame.includes(`${entry.name}@`)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
stackRef.current = frames.slice(index + 1).join('\n');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
callback();
|
|
160
|
+
} finally {
|
|
161
|
+
stackRef.current = undefined;
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
[]
|
|
165
|
+
);
|
|
166
|
+
|
|
128
167
|
const dispatch = useLatestCallback(
|
|
129
168
|
(
|
|
130
169
|
action: NavigationAction | ((state: NavigationState) => NavigationAction)
|
|
@@ -134,11 +173,13 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
134
173
|
if (listener == null) {
|
|
135
174
|
console.error(NOT_INITIALIZED_ERROR);
|
|
136
175
|
} else {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
176
|
+
withStackTrace(dispatch, () => {
|
|
177
|
+
listener((navigation) =>
|
|
178
|
+
React.startTransition(() => {
|
|
179
|
+
navigation.dispatch(action);
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
});
|
|
142
183
|
}
|
|
143
184
|
}
|
|
144
185
|
);
|
|
@@ -161,7 +202,7 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
161
202
|
|
|
162
203
|
const resetRoot = useLatestCallback(
|
|
163
204
|
(state: PartialState<NavigationState> | NavigationState) => {
|
|
164
|
-
const target =
|
|
205
|
+
const target = keyedListeners.getState.root?.().key;
|
|
165
206
|
const listener = listeners.focus[0];
|
|
166
207
|
|
|
167
208
|
if (target == null || listener == null) {
|
|
@@ -199,29 +240,28 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
199
240
|
|
|
200
241
|
const { addOptionsGetter, getCurrentOptions } = useOptionsGetters({});
|
|
201
242
|
|
|
202
|
-
const
|
|
243
|
+
const container: NavigationContainerRef<ParamList> = React.useMemo(
|
|
203
244
|
() => ({
|
|
204
245
|
...Object.keys(CommonActions).reduce<any>((acc, name) => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
246
|
+
const helper = (...args: any[]) =>
|
|
247
|
+
withStackTrace(helper, () =>
|
|
248
|
+
// @ts-expect-error: this is ok
|
|
249
|
+
dispatch(CommonActions[name](...args))
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
acc[name] = helper;
|
|
208
253
|
|
|
209
254
|
return acc;
|
|
210
255
|
}, {}),
|
|
211
256
|
...emitter.create('root'),
|
|
212
257
|
dispatch,
|
|
213
258
|
resetRoot,
|
|
214
|
-
isFocused: () => true,
|
|
215
259
|
canGoBack,
|
|
216
|
-
getParent: () => undefined,
|
|
217
260
|
getState,
|
|
218
261
|
getRootState,
|
|
219
262
|
getCurrentRoute,
|
|
220
263
|
getCurrentOptions,
|
|
221
264
|
isReady,
|
|
222
|
-
setOptions: () => {
|
|
223
|
-
throw new Error('Cannot call setOptions outside a screen');
|
|
224
|
-
},
|
|
225
265
|
}),
|
|
226
266
|
[
|
|
227
267
|
canGoBack,
|
|
@@ -233,10 +273,112 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
233
273
|
getState,
|
|
234
274
|
isReady,
|
|
235
275
|
resetRoot,
|
|
276
|
+
withStackTrace,
|
|
236
277
|
]
|
|
237
278
|
);
|
|
238
279
|
|
|
239
|
-
React.
|
|
280
|
+
const navigation: GenericNavigation<ParamListBase> = React.useMemo(() => {
|
|
281
|
+
const events = emitter.create('root');
|
|
282
|
+
|
|
283
|
+
const dispatch = (
|
|
284
|
+
thunk: NavigationAction | ((state: NavigationState) => NavigationAction)
|
|
285
|
+
) => {
|
|
286
|
+
const root = keyedListeners.getNavigation.root?.();
|
|
287
|
+
|
|
288
|
+
if (root == null) {
|
|
289
|
+
console.error(NOT_INITIALIZED_ERROR);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
withStackTrace(dispatch, () => {
|
|
294
|
+
React.startTransition(() => {
|
|
295
|
+
root.dispatch(thunk);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const helpers = Object.keys(CommonActions).reduce<any>((acc, name) => {
|
|
301
|
+
const helper = (...args: any) => {
|
|
302
|
+
if (
|
|
303
|
+
name === 'setParams' ||
|
|
304
|
+
name === 'replaceParams' ||
|
|
305
|
+
name === 'pushParams'
|
|
306
|
+
) {
|
|
307
|
+
throw new Error(`Cannot call ${name} outside a screen`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
withStackTrace(helper, () =>
|
|
311
|
+
// @ts-expect-error name is a valid key, but TypeScript cannot infer it.
|
|
312
|
+
dispatch(CommonActions[name](...args))
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
acc[name] = helper;
|
|
317
|
+
|
|
318
|
+
return acc;
|
|
319
|
+
}, {});
|
|
320
|
+
|
|
321
|
+
const listeners = new WeakMap<
|
|
322
|
+
(...args: never[]) => void,
|
|
323
|
+
EventListenerCallback<NavigationContainerEventMap, 'state'>
|
|
324
|
+
>();
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
...helpers,
|
|
328
|
+
dispatch,
|
|
329
|
+
addListener: (type, callback) => {
|
|
330
|
+
if (type === 'state') {
|
|
331
|
+
let listener = listeners.get(callback);
|
|
332
|
+
|
|
333
|
+
if (listener === undefined) {
|
|
334
|
+
// Root's state change events can contain stale and undefined state
|
|
335
|
+
// But navigation objects should only receive non-stale state
|
|
336
|
+
// So we add a wrapper to filter out stale events
|
|
337
|
+
listener = (event) => {
|
|
338
|
+
if (event.data.state?.stale === false) {
|
|
339
|
+
// @ts-expect-error TypeScript doesn't narrow the generic event callback with its type.
|
|
340
|
+
callback(event);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
listeners.set(callback, listener);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return events.addListener('state', listener);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return () => {};
|
|
351
|
+
},
|
|
352
|
+
removeListener: (type, callback) => {
|
|
353
|
+
if (type === 'state') {
|
|
354
|
+
const listener = listeners.get(callback);
|
|
355
|
+
|
|
356
|
+
if (listener) {
|
|
357
|
+
events.removeListener('state', listener);
|
|
358
|
+
listeners.delete(callback);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
canGoBack: () =>
|
|
363
|
+
keyedListeners.getNavigation.root?.().canGoBack() ?? false,
|
|
364
|
+
getState: () => keyedListeners.getState.root?.(),
|
|
365
|
+
getParent: (routeName?: string) => {
|
|
366
|
+
if (routeName !== undefined) {
|
|
367
|
+
throw new Error(
|
|
368
|
+
`Couldn't find a navigation object for '${routeName}' because it's called outside a screen. Is your component inside a screen?`
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return undefined;
|
|
373
|
+
},
|
|
374
|
+
setOptions: () => {
|
|
375
|
+
throw new Error('Cannot call setOptions outside a screen');
|
|
376
|
+
},
|
|
377
|
+
isFocused: () => true,
|
|
378
|
+
};
|
|
379
|
+
}, [emitter, keyedListeners, withStackTrace]);
|
|
380
|
+
|
|
381
|
+
React.useImperativeHandle(ref, () => container, [container]);
|
|
240
382
|
|
|
241
383
|
const onDispatchAction = useLatestCallback(
|
|
242
384
|
(action: NavigationAction, noop: boolean) => {
|
|
@@ -276,8 +418,6 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
276
418
|
});
|
|
277
419
|
});
|
|
278
420
|
|
|
279
|
-
const stackRef = React.useRef<string | undefined>(undefined);
|
|
280
|
-
|
|
281
421
|
const lastEmittedStateRef = React.useRef<State>(undefined);
|
|
282
422
|
|
|
283
423
|
const getIsStateEmitted = useLatestCallback(
|
|
@@ -294,7 +434,7 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
294
434
|
getIsStateEmitted,
|
|
295
435
|
scheduleUpdate,
|
|
296
436
|
flushUpdates,
|
|
297
|
-
|
|
437
|
+
withStackTrace,
|
|
298
438
|
}),
|
|
299
439
|
[
|
|
300
440
|
addListener,
|
|
@@ -305,6 +445,7 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
305
445
|
getIsStateEmitted,
|
|
306
446
|
scheduleUpdate,
|
|
307
447
|
flushUpdates,
|
|
448
|
+
withStackTrace,
|
|
308
449
|
]
|
|
309
450
|
);
|
|
310
451
|
|
|
@@ -317,12 +458,22 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
317
458
|
state,
|
|
318
459
|
getState,
|
|
319
460
|
setState,
|
|
461
|
+
subscribe,
|
|
320
462
|
getKey,
|
|
321
463
|
setKey,
|
|
322
464
|
getIsInitial,
|
|
323
465
|
addOptionsGetter,
|
|
324
466
|
}),
|
|
325
|
-
[
|
|
467
|
+
[
|
|
468
|
+
state,
|
|
469
|
+
getState,
|
|
470
|
+
setState,
|
|
471
|
+
subscribe,
|
|
472
|
+
getKey,
|
|
473
|
+
setKey,
|
|
474
|
+
getIsInitial,
|
|
475
|
+
addOptionsGetter,
|
|
476
|
+
]
|
|
326
477
|
);
|
|
327
478
|
|
|
328
479
|
const onReadyRef = React.useRef(onReady);
|
|
@@ -349,59 +500,6 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
349
500
|
|
|
350
501
|
if (process.env.NODE_ENV !== 'production') {
|
|
351
502
|
if (hydratedState !== undefined) {
|
|
352
|
-
const serializableResult = checkSerializable(hydratedState);
|
|
353
|
-
|
|
354
|
-
if (!serializableResult.serializable) {
|
|
355
|
-
const { location, reason } = serializableResult;
|
|
356
|
-
|
|
357
|
-
let path = '';
|
|
358
|
-
let pointer: Record<any, any> = hydratedState;
|
|
359
|
-
let params = false;
|
|
360
|
-
|
|
361
|
-
for (let i = 0; i < location.length; i++) {
|
|
362
|
-
const curr = location[i];
|
|
363
|
-
const prev = location[i - 1];
|
|
364
|
-
|
|
365
|
-
if (curr == null) {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
pointer = pointer[curr];
|
|
370
|
-
|
|
371
|
-
if (!params && curr === 'state') {
|
|
372
|
-
continue;
|
|
373
|
-
} else if (!params && curr === 'routes') {
|
|
374
|
-
if (path) {
|
|
375
|
-
path += ' > ';
|
|
376
|
-
}
|
|
377
|
-
} else if (
|
|
378
|
-
!params &&
|
|
379
|
-
typeof curr === 'number' &&
|
|
380
|
-
prev === 'routes'
|
|
381
|
-
) {
|
|
382
|
-
path += pointer?.name;
|
|
383
|
-
} else if (!params) {
|
|
384
|
-
path += ` > ${curr}`;
|
|
385
|
-
params = true;
|
|
386
|
-
} else {
|
|
387
|
-
if (typeof curr === 'number' || /^[0-9]+$/.test(curr)) {
|
|
388
|
-
path += `[${curr}]`;
|
|
389
|
-
} else if (/^[a-z$_]+$/i.test(curr)) {
|
|
390
|
-
path += `.${curr}`;
|
|
391
|
-
} else {
|
|
392
|
-
path += `[${JSON.stringify(curr)}]`;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
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.`;
|
|
398
|
-
|
|
399
|
-
if (!serializableWarnings.includes(message)) {
|
|
400
|
-
serializableWarnings.push(message);
|
|
401
|
-
console.warn(message);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
503
|
const duplicateRouteNamesResult =
|
|
406
504
|
checkDuplicateRouteNames(hydratedState);
|
|
407
505
|
|
|
@@ -410,10 +508,7 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
410
508
|
(locations) => `\n${locations.join(', ')}`
|
|
411
509
|
)}\n\nThis can cause confusing behavior during navigation. Consider using unique names for each screen instead.`;
|
|
412
510
|
|
|
413
|
-
|
|
414
|
-
duplicateNameWarnings.push(message);
|
|
415
|
-
console.warn(message);
|
|
416
|
-
}
|
|
511
|
+
warnOnce(true, message);
|
|
417
512
|
}
|
|
418
513
|
}
|
|
419
514
|
}
|
|
@@ -475,20 +570,22 @@ export function BaseNavigationContainer<ParamList extends {} = RootParamList>({
|
|
|
475
570
|
|
|
476
571
|
return (
|
|
477
572
|
<NavigationIndependentTreeContext.Provider value={false}>
|
|
478
|
-
<NavigationContainerRefContext.Provider value={
|
|
479
|
-
<
|
|
480
|
-
<
|
|
481
|
-
<
|
|
482
|
-
<
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
<
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
573
|
+
<NavigationContainerRefContext.Provider value={container}>
|
|
574
|
+
<NavigationRootContext.Provider value={navigation}>
|
|
575
|
+
<NavigationBuilderContext.Provider value={builderContext}>
|
|
576
|
+
<NavigationStateContext.Provider value={context}>
|
|
577
|
+
<ConsumedParamsContext.Provider value={consumedParams}>
|
|
578
|
+
<UnhandledActionContext.Provider
|
|
579
|
+
value={onUnhandledAction ?? defaultOnUnhandledAction}
|
|
580
|
+
>
|
|
581
|
+
<EnsureSingleNavigator>
|
|
582
|
+
<ThemeProvider value={theme}>{children}</ThemeProvider>
|
|
583
|
+
</EnsureSingleNavigator>
|
|
584
|
+
</UnhandledActionContext.Provider>
|
|
585
|
+
</ConsumedParamsContext.Provider>
|
|
586
|
+
</NavigationStateContext.Provider>
|
|
587
|
+
</NavigationBuilderContext.Provider>
|
|
588
|
+
</NavigationRootContext.Provider>
|
|
492
589
|
</NavigationContainerRefContext.Provider>
|
|
493
590
|
</NavigationIndependentTreeContext.Provider>
|
|
494
591
|
);
|
package/src/DataLoading.tsx
CHANGED
|
@@ -134,7 +134,10 @@ export function getLoaderForStateChange(
|
|
|
134
134
|
const nested =
|
|
135
135
|
'config' in item
|
|
136
136
|
? item
|
|
137
|
-
: 'screen' in item &&
|
|
137
|
+
: 'screen' in item &&
|
|
138
|
+
// Nested navigators cannot be defined as a getter
|
|
139
|
+
Object.getOwnPropertyDescriptor(item, 'screen')?.get == null &&
|
|
140
|
+
'config' in item.screen
|
|
138
141
|
? item.screen
|
|
139
142
|
: undefined;
|
|
140
143
|
|
|
@@ -15,6 +15,7 @@ export type ListenerMap = {
|
|
|
15
15
|
|
|
16
16
|
export type KeyedListenerMap = {
|
|
17
17
|
getState: GetStateListener;
|
|
18
|
+
getNavigation: GetNavigationListener;
|
|
18
19
|
beforeRemove: ChildBeforeRemoveListener;
|
|
19
20
|
};
|
|
20
21
|
|
|
@@ -47,6 +48,13 @@ export type FocusedNavigationListener = <T>(
|
|
|
47
48
|
|
|
48
49
|
export type GetStateListener = () => NavigationState;
|
|
49
50
|
|
|
51
|
+
export type GetNavigationListener = () => NavigationHelpers<ParamListBase>;
|
|
52
|
+
|
|
53
|
+
export type WithStackTrace = (
|
|
54
|
+
entry: (...args: never[]) => void,
|
|
55
|
+
callback: () => void
|
|
56
|
+
) => void;
|
|
57
|
+
|
|
50
58
|
export type ChildBeforeRemoveListener = (
|
|
51
59
|
action: NavigationAction,
|
|
52
60
|
nextState: NavigationState | PartialState<NavigationState> | undefined
|
|
@@ -73,7 +81,7 @@ export const NavigationBuilderContext = React.createContext<{
|
|
|
73
81
|
getIsStateEmitted: () => boolean;
|
|
74
82
|
scheduleUpdate: (callback: () => void) => void;
|
|
75
83
|
flushUpdates: () => void;
|
|
76
|
-
|
|
84
|
+
withStackTrace: WithStackTrace;
|
|
77
85
|
}>({
|
|
78
86
|
onDispatchAction: () => undefined,
|
|
79
87
|
onEmitEvent: () => undefined,
|
|
@@ -85,4 +93,5 @@ export const NavigationBuilderContext = React.createContext<{
|
|
|
85
93
|
flushUpdates: () => {
|
|
86
94
|
throw new Error("Couldn't find a context for flushing updates.");
|
|
87
95
|
},
|
|
96
|
+
withStackTrace: (_entry, callback) => callback(),
|
|
88
97
|
});
|
|
@@ -3,12 +3,17 @@ import * as React from 'react';
|
|
|
3
3
|
import { NavigationFocusedRouteStateContext } from './NavigationFocusedRouteStateContext';
|
|
4
4
|
import { NavigationIndependentTreeContext } from './NavigationIndependentTreeContext';
|
|
5
5
|
import {
|
|
6
|
+
IsScreenContext,
|
|
6
7
|
NamedRouteContextListContext,
|
|
7
8
|
NavigationContext,
|
|
8
9
|
NavigationRouteContext,
|
|
9
10
|
} from './NavigationProvider';
|
|
11
|
+
import { NavigationRootContext } from './NavigationRootContext';
|
|
10
12
|
import { IsFocusedContext } from './useIsFocused';
|
|
11
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
NamedNavigationStateListenerListContext,
|
|
15
|
+
NavigationStateListenerContext,
|
|
16
|
+
} from './useNavigationState';
|
|
12
17
|
|
|
13
18
|
/**
|
|
14
19
|
* Component to make the child navigation container independent of parent containers.
|
|
@@ -20,20 +25,26 @@ export function NavigationIndependentTree({
|
|
|
20
25
|
}) {
|
|
21
26
|
return (
|
|
22
27
|
// We need to clear any existing contexts for nested independent container to work correctly
|
|
23
|
-
<
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
<
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
<NavigationStateListenerContext.Provider value={undefined}>
|
|
29
|
+
<NamedNavigationStateListenerListContext.Provider value={undefined}>
|
|
30
|
+
<NamedRouteContextListContext.Provider value={undefined}>
|
|
31
|
+
<NavigationRouteContext.Provider value={undefined}>
|
|
32
|
+
<NavigationContext.Provider value={undefined}>
|
|
33
|
+
<NavigationRootContext.Provider value={undefined}>
|
|
34
|
+
<NavigationFocusedRouteStateContext.Provider value={undefined}>
|
|
35
|
+
<IsFocusedContext.Provider value={undefined}>
|
|
36
|
+
<NavigationIndependentTreeContext.Provider value={true}>
|
|
37
|
+
<IsScreenContext.Provider value={false}>
|
|
38
|
+
{children}
|
|
39
|
+
</IsScreenContext.Provider>
|
|
40
|
+
</NavigationIndependentTreeContext.Provider>
|
|
41
|
+
</IsFocusedContext.Provider>
|
|
42
|
+
</NavigationFocusedRouteStateContext.Provider>
|
|
43
|
+
</NavigationRootContext.Provider>
|
|
44
|
+
</NavigationContext.Provider>
|
|
45
|
+
</NavigationRouteContext.Provider>
|
|
46
|
+
</NamedRouteContextListContext.Provider>
|
|
47
|
+
</NamedNavigationStateListenerListContext.Provider>
|
|
48
|
+
</NavigationStateListenerContext.Provider>
|
|
38
49
|
);
|
|
39
50
|
}
|
|
@@ -20,11 +20,10 @@ export const NavigationContext = React.createContext<
|
|
|
20
20
|
NavigationProp<ParamListBase> | undefined
|
|
21
21
|
>(undefined);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
23
|
+
/**
|
|
24
|
+
* Context which indicates whether the component is inside a screen.
|
|
25
|
+
*/
|
|
26
|
+
export const IsScreenContext = React.createContext(false);
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* Component to provide the navigation and route contexts to its children.
|
|
@@ -33,6 +32,12 @@ export const NamedRouteContextListContext = React.createContext<
|
|
|
33
32
|
Record<string, React.Context<Route<string>>> | undefined
|
|
34
33
|
>(undefined);
|
|
35
34
|
|
|
35
|
+
type Props = {
|
|
36
|
+
route: Route<string>;
|
|
37
|
+
navigation: NavigationProp<ParamListBase>;
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
};
|
|
40
|
+
|
|
36
41
|
export function NavigationProvider({ route, navigation, children }: Props) {
|
|
37
42
|
const NamedRouteContext = useLazyValue(() => React.createContext(route));
|
|
38
43
|
|
|
@@ -64,7 +69,9 @@ export function NavigationProvider({ route, navigation, children }: Props) {
|
|
|
64
69
|
<NavigationRouteContext.Provider value={route}>
|
|
65
70
|
<NavigationContext.Provider value={navigation}>
|
|
66
71
|
<IsFocusedContext.Provider value={isFocused}>
|
|
67
|
-
{
|
|
72
|
+
<IsScreenContext.Provider value={true}>
|
|
73
|
+
{children}
|
|
74
|
+
</IsScreenContext.Provider>
|
|
68
75
|
</IsFocusedContext.Provider>
|
|
69
76
|
</NavigationContext.Provider>
|
|
70
77
|
</NavigationRouteContext.Provider>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ParamListBase } from '@react-navigation/routers';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { GenericNavigation } from './types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Context which holds the navigation object for components outside a screen.
|
|
8
|
+
*/
|
|
9
|
+
export const NavigationRootContext = React.createContext<
|
|
10
|
+
GenericNavigation<ParamListBase> | undefined
|
|
11
|
+
>(undefined);
|
|
@@ -13,6 +13,7 @@ export const NavigationStateContext = React.createContext<{
|
|
|
13
13
|
setState: (
|
|
14
14
|
state: NavigationState | PartialState<NavigationState> | undefined
|
|
15
15
|
) => void;
|
|
16
|
+
subscribe: (callback: () => void) => () => void;
|
|
16
17
|
getIsInitial: () => boolean;
|
|
17
18
|
addOptionsGetter?:
|
|
18
19
|
| ((key: string, getter: () => object | undefined | null) => void)
|
|
@@ -32,6 +33,9 @@ export const NavigationStateContext = React.createContext<{
|
|
|
32
33
|
get setState(): any {
|
|
33
34
|
throw new Error(MISSING_CONTEXT_ERROR);
|
|
34
35
|
},
|
|
36
|
+
get subscribe(): any {
|
|
37
|
+
throw new Error(MISSING_CONTEXT_ERROR);
|
|
38
|
+
},
|
|
35
39
|
get getIsInitial(): any {
|
|
36
40
|
throw new Error(MISSING_CONTEXT_ERROR);
|
|
37
41
|
},
|
package/src/SceneView.tsx
CHANGED
|
@@ -24,6 +24,7 @@ type Props<State extends NavigationState, ScreenOptions extends {}> = {
|
|
|
24
24
|
routeState: NavigationState | PartialState<NavigationState> | undefined;
|
|
25
25
|
getState: () => State;
|
|
26
26
|
setState: (state: State) => void;
|
|
27
|
+
subscribe: (callback: () => void) => () => void;
|
|
27
28
|
options: object;
|
|
28
29
|
clearOptions: () => void;
|
|
29
30
|
};
|
|
@@ -42,6 +43,7 @@ export function SceneView<
|
|
|
42
43
|
routeState,
|
|
43
44
|
getState,
|
|
44
45
|
setState,
|
|
46
|
+
subscribe,
|
|
45
47
|
options,
|
|
46
48
|
clearOptions,
|
|
47
49
|
}: Props<State, ScreenOptions>) {
|
|
@@ -152,6 +154,7 @@ export function SceneView<
|
|
|
152
154
|
state: routeState,
|
|
153
155
|
getState: getCurrentState,
|
|
154
156
|
setState: setCurrentState,
|
|
157
|
+
subscribe,
|
|
155
158
|
getKey,
|
|
156
159
|
setKey,
|
|
157
160
|
getIsInitial,
|
|
@@ -161,6 +164,7 @@ export function SceneView<
|
|
|
161
164
|
routeState,
|
|
162
165
|
getCurrentState,
|
|
163
166
|
setCurrentState,
|
|
167
|
+
subscribe,
|
|
164
168
|
getKey,
|
|
165
169
|
setKey,
|
|
166
170
|
getIsInitial,
|