@react-navigation/core 7.23.0 → 7.25.0
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 +48 -21
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/NavigationBuilderContext.js +7 -11
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +41 -10
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +2 -2
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +0 -1
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +25 -18
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +53 -18
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/types.js +7 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +5 -5
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +3 -1
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +6 -4
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +15 -27
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +17 -7
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationState.js +1 -1
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +2 -2
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetState.js +2 -2
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +2 -2
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOnRouteFocus.js +2 -2
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +4 -8
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +2 -2
- package/lib/module/useScheduleUpdate.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +11 -7
- 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.map +1 -1
- package/lib/typescript/src/NavigationStateContext.d.ts +0 -1
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -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/types.d.ts +49 -1
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts +2 -5
- package/lib/typescript/src/useNavigation.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.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +5 -0
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts +2 -0
- package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/package.json +14 -15
- package/src/BaseNavigationContainer.tsx +69 -31
- package/src/NavigationBuilderContext.tsx +27 -17
- package/src/NavigationIndependentTree.tsx +41 -13
- package/src/NavigationProvider.tsx +11 -8
- package/src/NavigationStateContext.tsx +0 -4
- package/src/PreventRemoveProvider.tsx +0 -1
- package/src/SceneView.tsx +22 -27
- package/src/StaticNavigation.tsx +71 -17
- package/src/types.tsx +76 -8
- package/src/useDescriptors.tsx +5 -4
- package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
- package/src/useKeyedChildListeners.tsx +1 -0
- package/src/useNavigation.tsx +2 -5
- package/src/useNavigationBuilder.tsx +5 -6
- package/src/useNavigationCache.tsx +14 -31
- package/src/useNavigationHelpers.tsx +18 -6
- package/src/useNavigationState.tsx +1 -1
- package/src/useOnAction.tsx +2 -2
- package/src/useOnGetState.tsx +2 -2
- package/src/useOnPreventRemove.tsx +2 -2
- package/src/useOnRouteFocus.tsx +2 -4
- package/src/useOptionsGetters.tsx +9 -6
- package/src/useScheduleUpdate.tsx +2 -4
package/src/StaticNavigation.tsx
CHANGED
|
@@ -356,6 +356,9 @@ const MemoizedScreen = React.memo(
|
|
|
356
356
|
|
|
357
357
|
MemoizedScreen.displayName = 'Memo(Screen)';
|
|
358
358
|
|
|
359
|
+
const hasPropertyGetter = (object: object, property: PropertyKey) =>
|
|
360
|
+
Object.getOwnPropertyDescriptor(object, property)?.get != null;
|
|
361
|
+
|
|
359
362
|
const getItemsFromScreens = (
|
|
360
363
|
Screen: React.ComponentType<any>,
|
|
361
364
|
screens: StaticConfigScreens<any, any, any, any, any>
|
|
@@ -366,18 +369,57 @@ const getItemsFromScreens = (
|
|
|
366
369
|
let useIf: (() => boolean) | undefined;
|
|
367
370
|
|
|
368
371
|
let isNavigator = false;
|
|
372
|
+
let getComponent: (() => React.ComponentType<any>) | undefined;
|
|
369
373
|
|
|
370
374
|
if ('screen' in item) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
+
if (hasPropertyGetter(item, 'screen')) {
|
|
376
|
+
const rest: Record<string, unknown> = {};
|
|
377
|
+
|
|
378
|
+
// Iterate over the keys to avoid triggering the getter for 'screen'
|
|
379
|
+
for (const key of Object.keys(item)) {
|
|
380
|
+
if (key === 'screen' || key === 'if') {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
rest[key] = Reflect.get(item, key);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
useIf = item.if;
|
|
388
|
+
props = rest;
|
|
389
|
+
|
|
390
|
+
getComponent = () => {
|
|
391
|
+
const screen = item.screen;
|
|
392
|
+
|
|
393
|
+
if (isValidElementType(screen)) {
|
|
394
|
+
return screen;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (
|
|
398
|
+
screen != null &&
|
|
399
|
+
typeof screen === 'object' &&
|
|
400
|
+
'config' in screen
|
|
401
|
+
) {
|
|
402
|
+
throw new Error(
|
|
403
|
+
`Got a navigator object for the screen '${name}' instead of a component. A navigator cannot be specified when using a getter.`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
375
406
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
407
|
+
throw new Error(
|
|
408
|
+
`Got an invalid screen component for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
|
|
409
|
+
);
|
|
410
|
+
};
|
|
411
|
+
} else {
|
|
412
|
+
const { screen, if: _if, ...rest } = item;
|
|
413
|
+
|
|
414
|
+
useIf = _if;
|
|
415
|
+
props = rest;
|
|
416
|
+
|
|
417
|
+
if (isValidElementType(screen)) {
|
|
418
|
+
component = screen;
|
|
419
|
+
} else if ('config' in screen) {
|
|
420
|
+
isNavigator = true;
|
|
421
|
+
component = screen.getComponent();
|
|
422
|
+
}
|
|
381
423
|
}
|
|
382
424
|
} else if (isValidElementType(item)) {
|
|
383
425
|
component = item;
|
|
@@ -386,18 +428,29 @@ const getItemsFromScreens = (
|
|
|
386
428
|
component = item.getComponent();
|
|
387
429
|
}
|
|
388
430
|
|
|
389
|
-
|
|
431
|
+
let children: (() => React.JSX.Element) | undefined;
|
|
432
|
+
|
|
433
|
+
if (getComponent != null) {
|
|
434
|
+
let element: React.JSX.Element | undefined;
|
|
435
|
+
|
|
436
|
+
children = () =>
|
|
437
|
+
(element ??= <MemoizedScreen component={getComponent()} />);
|
|
438
|
+
} else if (component != null) {
|
|
439
|
+
const element = isNavigator ? (
|
|
440
|
+
React.createElement(component, {})
|
|
441
|
+
) : (
|
|
442
|
+
<MemoizedScreen component={component} />
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
children = () => element;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (children == null) {
|
|
390
449
|
throw new Error(
|
|
391
450
|
`Couldn't find a 'screen' property for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
|
|
392
451
|
);
|
|
393
452
|
}
|
|
394
453
|
|
|
395
|
-
const element = isNavigator ? (
|
|
396
|
-
React.createElement(component, {})
|
|
397
|
-
) : (
|
|
398
|
-
<MemoizedScreen component={component} />
|
|
399
|
-
);
|
|
400
|
-
|
|
401
454
|
return () => {
|
|
402
455
|
const shouldRender = useIf == null || useIf();
|
|
403
456
|
|
|
@@ -407,7 +460,7 @@ const getItemsFromScreens = (
|
|
|
407
460
|
|
|
408
461
|
return (
|
|
409
462
|
<Screen key={name} name={name} {...props}>
|
|
410
|
-
{
|
|
463
|
+
{children}
|
|
411
464
|
</Screen>
|
|
412
465
|
);
|
|
413
466
|
};
|
|
@@ -732,6 +785,7 @@ export function createPathConfigForStaticNavigation(
|
|
|
732
785
|
!hasExplicitScreens &&
|
|
733
786
|
!hasDisabledLinking &&
|
|
734
787
|
'screen' in item &&
|
|
788
|
+
!hasPropertyGetter(item, 'screen') &&
|
|
735
789
|
'config' in item.screen &&
|
|
736
790
|
(item.screen.config.screens || item.screen.config.groups)
|
|
737
791
|
) {
|
package/src/types.tsx
CHANGED
|
@@ -312,9 +312,8 @@ export type EventArg<
|
|
|
312
312
|
export type EventListenerCallback<
|
|
313
313
|
EventMap extends EventMapBase,
|
|
314
314
|
EventName extends keyof EventMap,
|
|
315
|
-
EventCanPreventDefault extends
|
|
316
|
-
|
|
317
|
-
| undefined = EventMap[EventName]['canPreventDefault'],
|
|
315
|
+
EventCanPreventDefault extends boolean | undefined =
|
|
316
|
+
EventMap[EventName]['canPreventDefault'],
|
|
318
317
|
> = (
|
|
319
318
|
e: EventArg<
|
|
320
319
|
EventName,
|
|
@@ -642,6 +641,57 @@ export type NavigationProp<
|
|
|
642
641
|
EventConsumer<EventMap & EventMapCore<State>> &
|
|
643
642
|
PrivateValueStore<[ParamList, RouteName, EventMap]>;
|
|
644
643
|
|
|
644
|
+
/**
|
|
645
|
+
* A stripped down NavigationProp if the navigator is not known.
|
|
646
|
+
*
|
|
647
|
+
* The hook can be used in `NavigationContainer` directly, not inside of a navigator.
|
|
648
|
+
* So navigator specific methods won't be available.
|
|
649
|
+
*/
|
|
650
|
+
export type GenericNavigation<ParamList extends {}> = Omit<
|
|
651
|
+
NavigationProp<ParamList>,
|
|
652
|
+
'getState' | 'setParams' | 'replaceParams' | 'setOptions'
|
|
653
|
+
> & {
|
|
654
|
+
/**
|
|
655
|
+
* Returns the navigator's state.
|
|
656
|
+
*
|
|
657
|
+
* This may return `undefined` if used outside of a navigator,
|
|
658
|
+
* as the navigator may not have rendered yet
|
|
659
|
+
*/
|
|
660
|
+
getState(): NavigationState | undefined;
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Update the param object for the route.
|
|
664
|
+
* The new params will be shallow merged with the old one.
|
|
665
|
+
*
|
|
666
|
+
* @param params Partial params object for the current route.
|
|
667
|
+
*/
|
|
668
|
+
setParams(
|
|
669
|
+
// We don't know which route to set params for
|
|
670
|
+
params: unknown
|
|
671
|
+
): void;
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Replace the param object for the route
|
|
675
|
+
*
|
|
676
|
+
* @param params Params object for the current route.
|
|
677
|
+
*/
|
|
678
|
+
replaceParams(
|
|
679
|
+
// We don't know which route to replace params for
|
|
680
|
+
params: unknown
|
|
681
|
+
): void;
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Update the options for the route.
|
|
685
|
+
* The options object will be shallow merged with default options object.
|
|
686
|
+
*
|
|
687
|
+
* @param options Partial options object for the current screen.
|
|
688
|
+
*/
|
|
689
|
+
setOptions(
|
|
690
|
+
// We don't know which navigator to set options for
|
|
691
|
+
options: unknown
|
|
692
|
+
): void;
|
|
693
|
+
};
|
|
694
|
+
|
|
645
695
|
export type RouteProp<
|
|
646
696
|
ParamList extends ParamListBase,
|
|
647
697
|
RouteName extends keyof ParamList = Keyof<ParamList>,
|
|
@@ -1327,9 +1377,27 @@ export type PathConfig<ParamList extends {}> = Partial<PathConfigAlias> & {
|
|
|
1327
1377
|
};
|
|
1328
1378
|
|
|
1329
1379
|
export type PathConfigMap<ParamList extends {}> = {
|
|
1330
|
-
[RouteName in keyof ParamList]?:
|
|
1331
|
-
ParamList[RouteName]
|
|
1332
|
-
> extends NavigatorScreenParams<infer T extends {}>
|
|
1333
|
-
? string | PathConfig<T>
|
|
1334
|
-
: string | Omit<PathConfig<{}>, 'screens' | 'initialRouteName'>;
|
|
1380
|
+
[RouteName in keyof ParamList]?: PathConfigForParams<ParamList[RouteName]>;
|
|
1335
1381
|
};
|
|
1382
|
+
|
|
1383
|
+
type NavigatorRoutes<Params> = Extract<Params, { screen: PropertyKey }>;
|
|
1384
|
+
|
|
1385
|
+
type PathConfigForParams<Params> =
|
|
1386
|
+
| string
|
|
1387
|
+
| (Omit<PathConfig<{}>, 'screens' | 'initialRouteName'> &
|
|
1388
|
+
([NonNullable<Params>] extends [never]
|
|
1389
|
+
? unknown
|
|
1390
|
+
: [NonNullable<Params>] extends [
|
|
1391
|
+
NavigatorScreenParams<Record<PropertyKey, unknown>>,
|
|
1392
|
+
]
|
|
1393
|
+
? {
|
|
1394
|
+
initialRouteName?: NavigatorRoutes<Params>['screen'];
|
|
1395
|
+
screens?: {
|
|
1396
|
+
[Route in NavigatorRoutes<Params> as Route['screen']]?: PathConfigForParams<
|
|
1397
|
+
Route extends { params?: infer ChildParams }
|
|
1398
|
+
? ChildParams
|
|
1399
|
+
: never
|
|
1400
|
+
>;
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
: unknown));
|
package/src/useDescriptors.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type AddKeyedListener,
|
|
14
14
|
type AddListener,
|
|
15
15
|
NavigationBuilderContext,
|
|
16
|
+
useNavigationBuilderContext,
|
|
16
17
|
} from './NavigationBuilderContext';
|
|
17
18
|
import { NavigationProvider } from './NavigationProvider';
|
|
18
19
|
import { SceneView } from './SceneView';
|
|
@@ -149,9 +150,9 @@ export function useDescriptors<
|
|
|
149
150
|
onOptionsChange,
|
|
150
151
|
scheduleUpdate,
|
|
151
152
|
flushUpdates,
|
|
152
|
-
|
|
153
|
+
withStackTrace,
|
|
153
154
|
getIsStateEmitted,
|
|
154
|
-
} =
|
|
155
|
+
} = useNavigationBuilderContext();
|
|
155
156
|
|
|
156
157
|
const context = React.useMemo(
|
|
157
158
|
() => ({
|
|
@@ -166,7 +167,7 @@ export function useDescriptors<
|
|
|
166
167
|
getIsStateEmitted,
|
|
167
168
|
scheduleUpdate,
|
|
168
169
|
flushUpdates,
|
|
169
|
-
|
|
170
|
+
withStackTrace,
|
|
170
171
|
}),
|
|
171
172
|
[
|
|
172
173
|
navigation,
|
|
@@ -180,7 +181,7 @@ export function useDescriptors<
|
|
|
180
181
|
getIsStateEmitted,
|
|
181
182
|
scheduleUpdate,
|
|
182
183
|
flushUpdates,
|
|
183
|
-
|
|
184
|
+
withStackTrace,
|
|
184
185
|
]
|
|
185
186
|
);
|
|
186
187
|
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import {
|
|
5
5
|
type FocusedNavigationCallback,
|
|
6
6
|
type FocusedNavigationListener,
|
|
7
|
-
|
|
7
|
+
useNavigationBuilderContext,
|
|
8
8
|
} from './NavigationBuilderContext';
|
|
9
9
|
import type { NavigationHelpers } from './types';
|
|
10
10
|
|
|
@@ -20,7 +20,7 @@ export function useFocusedListenersChildrenAdapter({
|
|
|
20
20
|
navigation,
|
|
21
21
|
focusedListeners,
|
|
22
22
|
}: Options) {
|
|
23
|
-
const { addListener } =
|
|
23
|
+
const { addListener } = useNavigationBuilderContext();
|
|
24
24
|
|
|
25
25
|
const listener = React.useCallback(
|
|
26
26
|
(callback: FocusedNavigationCallback<any>) => {
|
package/src/useNavigation.tsx
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { type NavigationState } from '@react-navigation/routers';
|
|
2
1
|
import * as React from 'react';
|
|
3
2
|
|
|
4
3
|
import { NavigationContainerRefContext } from './NavigationContainerRefContext';
|
|
5
4
|
import { NavigationContext } from './NavigationContext';
|
|
6
|
-
import type {
|
|
5
|
+
import type { GenericNavigation } from './types';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Hook to access the navigation prop of the parent screen anywhere.
|
|
@@ -11,9 +10,7 @@ import type { NavigationProp } from './types';
|
|
|
11
10
|
* @returns Navigation prop of the parent screen.
|
|
12
11
|
*/
|
|
13
12
|
export function useNavigation<
|
|
14
|
-
T =
|
|
15
|
-
getState(): NavigationState | undefined;
|
|
16
|
-
},
|
|
13
|
+
T = GenericNavigation<ReactNavigation.RootParamList>,
|
|
17
14
|
>(): T {
|
|
18
15
|
const root = React.useContext(NavigationContainerRefContext);
|
|
19
16
|
const navigation = React.useContext(NavigationContext);
|
|
@@ -19,7 +19,7 @@ import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
|
19
19
|
import { deepFreeze } from './deepFreeze';
|
|
20
20
|
import { Group } from './Group';
|
|
21
21
|
import { isArrayEqual } from './isArrayEqual';
|
|
22
|
-
import {
|
|
22
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
23
23
|
import { NavigationHelpersContext } from './NavigationHelpersContext';
|
|
24
24
|
// eslint-disable-next-line import-x/no-deprecated
|
|
25
25
|
import { NavigationMetaContext } from './NavigationMetaContext';
|
|
@@ -431,6 +431,7 @@ export function useNavigationBuilder<
|
|
|
431
431
|
routeKeyList[name] = config.keys;
|
|
432
432
|
routeParamList[name] = config.props.initialParams;
|
|
433
433
|
|
|
434
|
+
// eslint-disable-next-line @eslint-react/purity
|
|
434
435
|
Object.assign(routeGetIdList, { [name]: config.props.getId });
|
|
435
436
|
}
|
|
436
437
|
|
|
@@ -463,9 +464,7 @@ export function useNavigationBuilder<
|
|
|
463
464
|
getIsInitial,
|
|
464
465
|
} = React.useContext(NavigationStateContext);
|
|
465
466
|
|
|
466
|
-
const { onEmitEvent, getIsStateEmitted } =
|
|
467
|
-
NavigationBuilderContext
|
|
468
|
-
);
|
|
467
|
+
const { onEmitEvent, getIsStateEmitted } = useNavigationBuilderContext();
|
|
469
468
|
|
|
470
469
|
const stateCleanupRef = React.useRef<boolean>(false);
|
|
471
470
|
const lastStateRef = React.useRef<State | PartialState<State> | undefined>(
|
|
@@ -609,7 +608,7 @@ export function useNavigationBuilder<
|
|
|
609
608
|
// Instead, we handle changes to these in the nextState code below. Note
|
|
610
609
|
// that some changes to routeConfigs are explicitly ignored, such as changes
|
|
611
610
|
// to initialParams
|
|
612
|
-
// eslint-disable-next-line react
|
|
611
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
613
612
|
}, [currentState, router, isStateValid]);
|
|
614
613
|
|
|
615
614
|
const previousRouteKeyListRef = React.useRef(routeKeyList);
|
|
@@ -854,7 +853,7 @@ export function useNavigationBuilder<
|
|
|
854
853
|
// causing the initial state to be lost after cleanup wipes the container state.
|
|
855
854
|
lastNotifiedStateRef.current = null;
|
|
856
855
|
};
|
|
857
|
-
// eslint-disable-next-line react
|
|
856
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
858
857
|
}, []);
|
|
859
858
|
|
|
860
859
|
const getState = useLatestCallback((): State => {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from '@react-navigation/routers';
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
11
11
|
import type { NavigationHelpers, NavigationProp } from './types';
|
|
12
12
|
import type { NavigationEventEmitter } from './useEventEmitter';
|
|
13
13
|
|
|
@@ -66,7 +66,7 @@ export function useNavigationCache<
|
|
|
66
66
|
router,
|
|
67
67
|
emitter,
|
|
68
68
|
}: Options<State, ScreenOptions, EventMap>) {
|
|
69
|
-
const {
|
|
69
|
+
const { withStackTrace } = useNavigationBuilderContext();
|
|
70
70
|
|
|
71
71
|
const base = React.useMemo((): NavigationItem<
|
|
72
72
|
State,
|
|
@@ -130,7 +130,7 @@ export function useNavigationCache<
|
|
|
130
130
|
// In reality, these deps will rarely change, if ever
|
|
131
131
|
const cache = React.useMemo(
|
|
132
132
|
() => ({ current: {} as NavigationCache<State, ScreenOptions, EventMap> }),
|
|
133
|
-
// eslint-disable-next-line react
|
|
133
|
+
// eslint-disable-next-line @eslint-react/exhaustive-deps
|
|
134
134
|
[base, getState, navigation, setOptions, emitter]
|
|
135
135
|
);
|
|
136
136
|
|
|
@@ -148,33 +148,14 @@ export function useNavigationCache<
|
|
|
148
148
|
acc[route.key] = previous;
|
|
149
149
|
} else {
|
|
150
150
|
const dispatch = (thunk: Thunk) => {
|
|
151
|
-
|
|
151
|
+
withStackTrace(dispatch, () => {
|
|
152
|
+
const action =
|
|
153
|
+
typeof thunk === 'function' ? thunk(getState()) : thunk;
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const withStack = (callback: () => void) => {
|
|
159
|
-
let isStackSet = false;
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
if (
|
|
163
|
-
process.env.NODE_ENV !== 'production' &&
|
|
164
|
-
stackRef &&
|
|
165
|
-
!stackRef.current
|
|
166
|
-
) {
|
|
167
|
-
// Capture the stack trace for devtools
|
|
168
|
-
stackRef.current = new Error().stack;
|
|
169
|
-
isStackSet = true;
|
|
155
|
+
if (action != null) {
|
|
156
|
+
navigation.dispatch({ source: route.key, ...action });
|
|
170
157
|
}
|
|
171
|
-
|
|
172
|
-
callback();
|
|
173
|
-
} finally {
|
|
174
|
-
if (isStackSet && stackRef) {
|
|
175
|
-
stackRef.current = undefined;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
158
|
+
});
|
|
178
159
|
};
|
|
179
160
|
|
|
180
161
|
const actions = {
|
|
@@ -184,12 +165,14 @@ export function useNavigationCache<
|
|
|
184
165
|
|
|
185
166
|
const helpers = Object.keys(actions).reduce<Record<string, () => void>>(
|
|
186
167
|
(acc, name) => {
|
|
187
|
-
|
|
188
|
-
|
|
168
|
+
const helper = (...args: any) =>
|
|
169
|
+
withStackTrace(helper, () =>
|
|
189
170
|
// @ts-expect-error: name is a valid key, but TypeScript is dumb
|
|
190
171
|
dispatch(actions[name](...args))
|
|
191
172
|
);
|
|
192
173
|
|
|
174
|
+
acc[name] = helper;
|
|
175
|
+
|
|
193
176
|
return acc;
|
|
194
177
|
},
|
|
195
178
|
{}
|
|
@@ -200,7 +183,7 @@ export function useNavigationCache<
|
|
|
200
183
|
...helpers,
|
|
201
184
|
// FIXME: too much work to fix the types for now
|
|
202
185
|
...(emitter.create(route.key) as any),
|
|
203
|
-
dispatch
|
|
186
|
+
dispatch,
|
|
204
187
|
getParent: (id?: string) => {
|
|
205
188
|
if (id !== undefined && id === base.getId()) {
|
|
206
189
|
// If the passed id is the same as the current navigation id,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@react-navigation/routers';
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
|
|
10
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
10
11
|
import { NavigationContext } from './NavigationContext';
|
|
11
12
|
import { type NavigationHelpers, PrivateValueStore } from './types';
|
|
12
13
|
import type { NavigationEventEmitter } from './useEventEmitter';
|
|
@@ -44,6 +45,7 @@ export function useNavigationHelpers<
|
|
|
44
45
|
router,
|
|
45
46
|
}: Options<State, Action>) {
|
|
46
47
|
const parentNavigationHelpers = React.useContext(NavigationContext);
|
|
48
|
+
const { withStackTrace } = useNavigationBuilderContext();
|
|
47
49
|
|
|
48
50
|
// In some cases (e.g. route names change), internal state might have changed
|
|
49
51
|
// But it hasn't been committed yet, so hasn't propagated to any listeners
|
|
@@ -64,13 +66,15 @@ export function useNavigationHelpers<
|
|
|
64
66
|
|
|
65
67
|
return React.useMemo(() => {
|
|
66
68
|
const dispatch = (op: Action | ((state: State) => Action)) => {
|
|
67
|
-
|
|
69
|
+
withStackTrace(dispatch, () => {
|
|
70
|
+
const action = typeof op === 'function' ? op(getState()) : op;
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
const handled = onAction(action);
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
if (!handled) {
|
|
75
|
+
onUnhandledAction?.(action);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
74
78
|
};
|
|
75
79
|
|
|
76
80
|
const actions = {
|
|
@@ -79,8 +83,15 @@ export function useNavigationHelpers<
|
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
const helpers = Object.keys(actions).reduce((acc, name) => {
|
|
86
|
+
const helper = (...args: any) =>
|
|
87
|
+
withStackTrace(helper, () =>
|
|
88
|
+
// @ts-expect-error: name is a valid key, but TypeScript is dumb
|
|
89
|
+
dispatch(actions[name](...args))
|
|
90
|
+
);
|
|
91
|
+
|
|
82
92
|
// @ts-expect-error: name is a valid key, but TypeScript is dumb
|
|
83
|
-
acc[name] =
|
|
93
|
+
acc[name] = helper;
|
|
94
|
+
|
|
84
95
|
return acc;
|
|
85
96
|
}, {} as ActionHelpers);
|
|
86
97
|
|
|
@@ -143,5 +154,6 @@ export function useNavigationHelpers<
|
|
|
143
154
|
onUnhandledAction,
|
|
144
155
|
navigatorId,
|
|
145
156
|
stateRef,
|
|
157
|
+
withStackTrace,
|
|
146
158
|
]);
|
|
147
159
|
}
|
|
@@ -108,6 +108,6 @@ export function NavigationStateListenerProvider({
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const NavigationStateListenerContext = React.createContext<
|
|
111
|
+
export const NavigationStateListenerContext = React.createContext<
|
|
112
112
|
NavigationStateListener | undefined
|
|
113
113
|
>(undefined);
|
package/src/useOnAction.tsx
CHANGED
|
@@ -11,7 +11,7 @@ import { DeprecatedNavigationInChildContext } from './DeprecatedNavigationInChil
|
|
|
11
11
|
import {
|
|
12
12
|
type ChildActionListener,
|
|
13
13
|
type ChildBeforeRemoveListener,
|
|
14
|
-
|
|
14
|
+
useNavigationBuilderContext,
|
|
15
15
|
} from './NavigationBuilderContext';
|
|
16
16
|
import type { EventMapCore } from './types';
|
|
17
17
|
import type { NavigationEventEmitter } from './useEventEmitter';
|
|
@@ -53,7 +53,7 @@ export function useOnAction<State extends NavigationState>({
|
|
|
53
53
|
addListener: addListenerParent,
|
|
54
54
|
onDispatchAction,
|
|
55
55
|
flushUpdates,
|
|
56
|
-
} =
|
|
56
|
+
} = useNavigationBuilderContext();
|
|
57
57
|
const navigationInChildEnabled = React.useContext(
|
|
58
58
|
DeprecatedNavigationInChildContext
|
|
59
59
|
);
|
package/src/useOnGetState.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { isArrayEqual } from './isArrayEqual';
|
|
5
5
|
import {
|
|
6
6
|
type GetStateListener,
|
|
7
|
-
|
|
7
|
+
useNavigationBuilderContext,
|
|
8
8
|
} from './NavigationBuilderContext';
|
|
9
9
|
import { NavigationRouteContext } from './NavigationProvider';
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ type Options = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
17
|
-
const { addKeyedListener } =
|
|
17
|
+
const { addKeyedListener } = useNavigationBuilderContext();
|
|
18
18
|
const route = React.useContext(NavigationRouteContext);
|
|
19
19
|
const key = route ? route.key : 'root';
|
|
20
20
|
|
|
@@ -9,7 +9,7 @@ import * as React from 'react';
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
type ChildBeforeRemoveListener,
|
|
12
|
-
|
|
12
|
+
useNavigationBuilderContext,
|
|
13
13
|
} from './NavigationBuilderContext';
|
|
14
14
|
import { NavigationRouteContext } from './NavigationProvider';
|
|
15
15
|
import type { EventMapCore } from './types';
|
|
@@ -107,7 +107,7 @@ export function useOnPreventRemove({
|
|
|
107
107
|
emitter,
|
|
108
108
|
beforeRemoveListeners,
|
|
109
109
|
}: Options) {
|
|
110
|
-
const { addKeyedListener } =
|
|
110
|
+
const { addKeyedListener } = useNavigationBuilderContext();
|
|
111
111
|
const route = React.useContext(NavigationRouteContext);
|
|
112
112
|
const routeKey = route?.key;
|
|
113
113
|
|
package/src/useOnRouteFocus.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
} from '@react-navigation/routers';
|
|
6
6
|
import * as React from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
9
9
|
|
|
10
10
|
type Options<State extends NavigationState, Action extends NavigationAction> = {
|
|
11
11
|
router: Router<State, Action>;
|
|
@@ -23,9 +23,7 @@ export function useOnRouteFocus<
|
|
|
23
23
|
State extends NavigationState,
|
|
24
24
|
Action extends NavigationAction,
|
|
25
25
|
>({ router, getState, key: sourceRouteKey, setState }: Options<State, Action>) {
|
|
26
|
-
const { onRouteFocus: onRouteFocusParent } =
|
|
27
|
-
NavigationBuilderContext
|
|
28
|
-
);
|
|
26
|
+
const { onRouteFocus: onRouteFocusParent } = useNavigationBuilderContext();
|
|
29
27
|
|
|
30
28
|
return React.useCallback(
|
|
31
29
|
(key: string) => {
|
|
@@ -2,9 +2,12 @@ import type { ParamListBase } from '@react-navigation/routers';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
5
|
-
import { NavigationStateContext } from './NavigationStateContext';
|
|
6
5
|
import type { NavigationProp } from './types';
|
|
7
6
|
|
|
7
|
+
export const OptionsGetterContext = React.createContext<
|
|
8
|
+
((key: string, getter: () => object | undefined | null) => void) | undefined
|
|
9
|
+
>(undefined);
|
|
10
|
+
|
|
8
11
|
type Options = {
|
|
9
12
|
key?: string;
|
|
10
13
|
navigation?: NavigationProp<ParamListBase>;
|
|
@@ -17,17 +20,17 @@ export function useOptionsGetters({ key, options, navigation }: Options) {
|
|
|
17
20
|
Record<string, () => object | undefined | null>
|
|
18
21
|
>({});
|
|
19
22
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
23
|
+
const onOptionsChange = React.useContext(
|
|
24
|
+
NavigationBuilderContext
|
|
25
|
+
)?.onOptionsChange;
|
|
26
|
+
const parentAddOptionsGetter = React.useContext(OptionsGetterContext);
|
|
24
27
|
|
|
25
28
|
const optionsChangeListener = React.useCallback(() => {
|
|
26
29
|
const isFocused = navigation?.isFocused() ?? true;
|
|
27
30
|
const hasChildren = Object.keys(optionsGettersFromChildRef.current).length;
|
|
28
31
|
|
|
29
32
|
if (isFocused && !hasChildren) {
|
|
30
|
-
onOptionsChange(optionsRef.current ?? {});
|
|
33
|
+
onOptionsChange?.(optionsRef.current ?? {});
|
|
31
34
|
}
|
|
32
35
|
}, [navigation, onOptionsChange]);
|
|
33
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useNavigationBuilderContext } from './NavigationBuilderContext';
|
|
4
4
|
import { useClientLayoutEffect } from './useClientLayoutEffect';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -12,9 +12,7 @@ import { useClientLayoutEffect } from './useClientLayoutEffect';
|
|
|
12
12
|
* This lets nested updates be applied from the root down without clobbering each other.
|
|
13
13
|
*/
|
|
14
14
|
export function useScheduleUpdate(callback: () => void) {
|
|
15
|
-
const { scheduleUpdate, flushUpdates } =
|
|
16
|
-
NavigationBuilderContext
|
|
17
|
-
);
|
|
15
|
+
const { scheduleUpdate, flushUpdates } = useNavigationBuilderContext();
|
|
18
16
|
|
|
19
17
|
React.useInsertionEffect(() => {
|
|
20
18
|
scheduleUpdate(callback);
|