@react-navigation/core 8.0.0-alpha.1 → 8.0.0-alpha.11
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 +14 -7
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/ConsumedParamsContext.js +5 -0
- package/lib/module/ConsumedParamsContext.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +1 -0
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +8 -4
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +14 -3
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +3 -3
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +46 -56
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +34 -4
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/createNavigatorFactory.js +22 -1
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/getPathFromState.js +25 -3
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +158 -73
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +24 -0
- package/lib/module/getStateFromRouteParams.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/theming/useTheme.js +1 -1
- package/lib/module/theming/useTheme.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useCurrentRender.js +1 -1
- package/lib/module/useCurrentRender.js.map +1 -1
- package/lib/module/useDescriptors.js +12 -43
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useFocusEvents.js +1 -1
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
- package/lib/module/useIsFocused.js +7 -12
- package/lib/module/useIsFocused.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +84 -38
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +14 -56
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +1 -1
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationIndependentTree.js +1 -1
- package/lib/module/useNavigationIndependentTree.js.map +1 -1
- package/lib/module/useNavigationState.js +4 -2
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +1 -1
- 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 +1 -1
- package/lib/module/useOnRouteFocus.js.map +1 -1
- package/lib/module/useOptionsGetters.js +2 -2
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +1 -1
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +1 -1
- package/lib/module/useRegisterNavigator.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +1 -1
- package/lib/module/useScheduleUpdate.js.map +1 -1
- package/lib/module/useStateForPath.js +1 -1
- package/lib/module/useStateForPath.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/ConsumedParamsContext.d.ts +8 -0
- package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationBuilderContext.d.ts +11 -5
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
- package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +4 -4
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/StaticContainer.d.ts +1 -1
- package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts +39 -24
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
- package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts +3 -3
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts +2 -2
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +3 -3
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
- package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +144 -82
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +12 -25
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useIsFocused.d.ts +3 -0
- package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +20 -29
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +2 -42
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +18 -16
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts +6 -6
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
- package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +2 -2
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +42 -3
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/package.json +20 -18
- package/src/BaseNavigationContainer.tsx +332 -326
- package/src/ConsumedParamsContext.tsx +10 -0
- package/src/NavigationBuilderContext.tsx +14 -8
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +8 -5
- package/src/NavigationProvider.tsx +17 -3
- package/src/NavigationStateContext.tsx +5 -6
- package/src/PreventRemoveProvider.tsx +3 -3
- package/src/SceneView.tsx +58 -56
- package/src/StaticNavigation.tsx +121 -51
- package/src/createNavigatorFactory.tsx +35 -4
- package/src/findFocusedRoute.tsx +3 -3
- package/src/getActionFromState.tsx +7 -7
- package/src/getPathFromState.tsx +53 -9
- package/src/getStateFromPath.tsx +255 -97
- package/src/getStateFromRouteParams.tsx +60 -0
- package/src/index.tsx +1 -1
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +330 -187
- package/src/useCurrentRender.tsx +1 -1
- package/src/useDescriptors.tsx +13 -48
- package/src/useFocusEvents.tsx +1 -1
- package/src/useFocusedListenersChildrenAdapter.tsx +1 -1
- package/src/useIsFocused.tsx +14 -21
- package/src/useNavigation.tsx +2 -2
- package/src/useNavigationBuilder.tsx +131 -49
- package/src/useNavigationCache.tsx +12 -73
- package/src/useNavigationHelpers.tsx +1 -1
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +6 -4
- package/src/useOnAction.tsx +8 -8
- package/src/useOnGetState.tsx +2 -2
- package/src/useOnPreventRemove.tsx +2 -2
- package/src/useOnRouteFocus.tsx +10 -12
- package/src/useOptionsGetters.tsx +2 -2
- package/src/usePreventRemoveContext.tsx +1 -1
- package/src/useRegisterNavigator.tsx +1 -1
- package/src/useScheduleUpdate.tsx +1 -3
- package/src/useStateForPath.tsx +1 -1
- package/src/utilities.tsx +94 -4
package/src/useCurrentRender.tsx
CHANGED
|
@@ -23,7 +23,7 @@ type Options = {
|
|
|
23
23
|
* Mutating values like this is not safe in async mode, but it doesn't apply to SSR
|
|
24
24
|
*/
|
|
25
25
|
export function useCurrentRender({ state, navigation, descriptors }: Options) {
|
|
26
|
-
const current = React.
|
|
26
|
+
const current = React.use(CurrentRenderContext);
|
|
27
27
|
|
|
28
28
|
if (current && navigation.isFocused()) {
|
|
29
29
|
current.options = descriptors[state.routes[state.index].key].options;
|
package/src/useDescriptors.tsx
CHANGED
|
@@ -67,7 +67,7 @@ type Options<
|
|
|
67
67
|
ScreenOptions extends {},
|
|
68
68
|
EventMap extends EventMapBase,
|
|
69
69
|
> = {
|
|
70
|
-
|
|
70
|
+
routes: State['routes'];
|
|
71
71
|
screens: Record<
|
|
72
72
|
string,
|
|
73
73
|
ScreenConfigWithParent<State, ScreenOptions, EventMap>
|
|
@@ -99,7 +99,7 @@ export function useDescriptors<
|
|
|
99
99
|
ScreenOptions extends {},
|
|
100
100
|
EventMap extends EventMapBase,
|
|
101
101
|
>({
|
|
102
|
-
|
|
102
|
+
routes,
|
|
103
103
|
screens,
|
|
104
104
|
navigation,
|
|
105
105
|
screenOptions,
|
|
@@ -113,17 +113,18 @@ export function useDescriptors<
|
|
|
113
113
|
router,
|
|
114
114
|
emitter,
|
|
115
115
|
}: Options<State, ScreenOptions, EventMap>) {
|
|
116
|
-
const theme = React.
|
|
116
|
+
const theme = React.use(ThemeContext);
|
|
117
117
|
const [options, setOptions] = React.useState<Record<string, ScreenOptions>>(
|
|
118
118
|
{}
|
|
119
119
|
);
|
|
120
120
|
const {
|
|
121
121
|
onDispatchAction,
|
|
122
|
+
onEmitEvent,
|
|
122
123
|
onOptionsChange,
|
|
123
124
|
scheduleUpdate,
|
|
124
125
|
flushUpdates,
|
|
125
126
|
stackRef,
|
|
126
|
-
} = React.
|
|
127
|
+
} = React.use(NavigationBuilderContext);
|
|
127
128
|
|
|
128
129
|
const context = React.useMemo(
|
|
129
130
|
() => ({
|
|
@@ -133,6 +134,7 @@ export function useDescriptors<
|
|
|
133
134
|
addKeyedListener,
|
|
134
135
|
onRouteFocus,
|
|
135
136
|
onDispatchAction,
|
|
137
|
+
onEmitEvent,
|
|
136
138
|
onOptionsChange,
|
|
137
139
|
scheduleUpdate,
|
|
138
140
|
flushUpdates,
|
|
@@ -145,6 +147,7 @@ export function useDescriptors<
|
|
|
145
147
|
addKeyedListener,
|
|
146
148
|
onRouteFocus,
|
|
147
149
|
onDispatchAction,
|
|
150
|
+
onEmitEvent,
|
|
148
151
|
onOptionsChange,
|
|
149
152
|
scheduleUpdate,
|
|
150
153
|
flushUpdates,
|
|
@@ -152,13 +155,13 @@ export function useDescriptors<
|
|
|
152
155
|
]
|
|
153
156
|
);
|
|
154
157
|
|
|
155
|
-
const
|
|
158
|
+
const navigations = useNavigationCache<
|
|
156
159
|
State,
|
|
157
160
|
ScreenOptions,
|
|
158
161
|
EventMap,
|
|
159
162
|
ActionHelpers
|
|
160
163
|
>({
|
|
161
|
-
|
|
164
|
+
routes,
|
|
162
165
|
getState,
|
|
163
166
|
navigation,
|
|
164
167
|
setOptions,
|
|
@@ -166,7 +169,7 @@ export function useDescriptors<
|
|
|
166
169
|
emitter,
|
|
167
170
|
});
|
|
168
171
|
|
|
169
|
-
const
|
|
172
|
+
const cachedRoutes = useRouteCache(routes);
|
|
170
173
|
|
|
171
174
|
const getOptions = (
|
|
172
175
|
route: RouteProp<ParamListBase, string>,
|
|
@@ -273,7 +276,7 @@ export function useDescriptors<
|
|
|
273
276
|
);
|
|
274
277
|
};
|
|
275
278
|
|
|
276
|
-
const descriptors =
|
|
279
|
+
const descriptors = cachedRoutes.reduce<
|
|
277
280
|
Record<
|
|
278
281
|
string,
|
|
279
282
|
Descriptor<
|
|
@@ -292,12 +295,7 @@ export function useDescriptors<
|
|
|
292
295
|
>((acc, route, i) => {
|
|
293
296
|
const navigation = navigations[route.key];
|
|
294
297
|
const customOptions = getOptions(route, navigation, options[route.key]);
|
|
295
|
-
const element = render(
|
|
296
|
-
route,
|
|
297
|
-
navigation,
|
|
298
|
-
customOptions,
|
|
299
|
-
state.routes[i].state
|
|
300
|
-
);
|
|
298
|
+
const element = render(route, navigation, customOptions, routes[i]?.state);
|
|
301
299
|
|
|
302
300
|
acc[route.key] = {
|
|
303
301
|
route,
|
|
@@ -311,38 +309,5 @@ export function useDescriptors<
|
|
|
311
309
|
return acc;
|
|
312
310
|
}, {});
|
|
313
311
|
|
|
314
|
-
|
|
315
|
-
* Create a descriptor object for a route.
|
|
316
|
-
*
|
|
317
|
-
* @param route Route object for which the descriptor should be created
|
|
318
|
-
* @param placeholder Whether the descriptor should be a placeholder, e.g. for a route not yet in the state
|
|
319
|
-
* @returns Descriptor object
|
|
320
|
-
*/
|
|
321
|
-
const describe = (route: RouteProp<ParamListBase>, placeholder: boolean) => {
|
|
322
|
-
if (!placeholder) {
|
|
323
|
-
if (!(route.key in descriptors)) {
|
|
324
|
-
throw new Error(`Couldn't find a route with the key ${route.key}.`);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return descriptors[route.key];
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const navigation = base;
|
|
331
|
-
const customOptions = getOptions(route, navigation, {});
|
|
332
|
-
const element = render(route, navigation, customOptions, undefined);
|
|
333
|
-
|
|
334
|
-
return {
|
|
335
|
-
route,
|
|
336
|
-
navigation,
|
|
337
|
-
render() {
|
|
338
|
-
return element;
|
|
339
|
-
},
|
|
340
|
-
options: customOptions as ScreenOptions,
|
|
341
|
-
};
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
return {
|
|
345
|
-
describe,
|
|
346
|
-
descriptors,
|
|
347
|
-
};
|
|
312
|
+
return descriptors;
|
|
348
313
|
}
|
package/src/useFocusEvents.tsx
CHANGED
|
@@ -17,7 +17,7 @@ export function useFocusEvents<State extends NavigationState>({
|
|
|
17
17
|
state,
|
|
18
18
|
emitter,
|
|
19
19
|
}: Options<State>) {
|
|
20
|
-
const navigation = React.
|
|
20
|
+
const navigation = React.use(NavigationContext);
|
|
21
21
|
const lastFocusedKeyRef = React.useRef<string | undefined>(undefined);
|
|
22
22
|
|
|
23
23
|
const currentFocusedKey = state.routes[state.index].key;
|
|
@@ -20,7 +20,7 @@ export function useFocusedListenersChildrenAdapter({
|
|
|
20
20
|
navigation,
|
|
21
21
|
focusedListeners,
|
|
22
22
|
}: Options) {
|
|
23
|
-
const { addListener } = React.
|
|
23
|
+
const { addListener } = React.use(NavigationBuilderContext);
|
|
24
24
|
|
|
25
25
|
const listener = React.useCallback(
|
|
26
26
|
(callback: FocusedNavigationCallback<any>) => {
|
package/src/useIsFocused.tsx
CHANGED
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export const FocusedRouteKeyContext = React.createContext<string | undefined>(
|
|
4
|
+
undefined
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
export const IsFocusedContext = React.createContext<boolean | undefined>(
|
|
8
|
+
undefined
|
|
9
|
+
);
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* Hook to get the current focus state of the screen. Returns a `true` if screen is focused, otherwise `false`.
|
|
7
13
|
* This can be used if a component needs to render something based on the focus state.
|
|
8
14
|
*/
|
|
9
15
|
export function useIsFocused(): boolean {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const subscribe = React.useCallback(
|
|
13
|
-
(callback: () => void) => {
|
|
14
|
-
const unsubscribeFocus = navigation.addListener('focus', callback);
|
|
15
|
-
const unsubscribeBlur = navigation.addListener('blur', callback);
|
|
16
|
-
|
|
17
|
-
return () => {
|
|
18
|
-
unsubscribeFocus();
|
|
19
|
-
unsubscribeBlur();
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
[navigation]
|
|
23
|
-
);
|
|
16
|
+
const isFocused = React.use(IsFocusedContext);
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
if (isFocused === undefined) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"Couldn't determine focus state. Is your component inside a screen in a navigator?"
|
|
21
|
+
);
|
|
22
|
+
}
|
|
30
23
|
|
|
31
|
-
return
|
|
24
|
+
return isFocused;
|
|
32
25
|
}
|
package/src/useNavigation.tsx
CHANGED
|
@@ -27,8 +27,8 @@ export function useNavigation<
|
|
|
27
27
|
>(): NavigationListForNavigator<Navigator>[keyof NavigationListForNavigator<Navigator>];
|
|
28
28
|
export function useNavigation<
|
|
29
29
|
const Navigator = RootNavigator,
|
|
30
|
-
const RouteName extends
|
|
31
|
-
keyof NavigationListForNested<Navigator
|
|
30
|
+
const RouteName extends keyof NavigationListForNested<Navigator> =
|
|
31
|
+
keyof NavigationListForNested<Navigator>,
|
|
32
32
|
>(name: RouteName): NavigationListForNested<Navigator>[RouteName];
|
|
33
33
|
export function useNavigation(name?: string): unknown {
|
|
34
34
|
const root = React.use(NavigationContainerRefContext);
|
|
@@ -15,10 +15,12 @@ import * as React from 'react';
|
|
|
15
15
|
import { isValidElementType } from 'react-is';
|
|
16
16
|
import useLatestCallback from 'use-latest-callback';
|
|
17
17
|
|
|
18
|
+
import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
18
19
|
import { deepFreeze } from './deepFreeze';
|
|
19
20
|
import { Group } from './Group';
|
|
20
21
|
import { isArrayEqual } from './isArrayEqual';
|
|
21
22
|
import { isRecordEqual } from './isRecordEqual';
|
|
23
|
+
import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
22
24
|
import { NavigationHelpersContext } from './NavigationHelpersContext';
|
|
23
25
|
import { NavigationMetaContext } from './NavigationMetaContext';
|
|
24
26
|
import { NavigationRouteContext } from './NavigationProvider';
|
|
@@ -41,6 +43,7 @@ import { type ScreenConfigWithParent, useDescriptors } from './useDescriptors';
|
|
|
41
43
|
import { useEventEmitter } from './useEventEmitter';
|
|
42
44
|
import { useFocusedListenersChildrenAdapter } from './useFocusedListenersChildrenAdapter';
|
|
43
45
|
import { useFocusEvents } from './useFocusEvents';
|
|
46
|
+
import { FocusedRouteKeyContext } from './useIsFocused';
|
|
44
47
|
import { useKeyedChildListeners } from './useKeyedChildListeners';
|
|
45
48
|
import { useLazyValue } from './useLazyValue';
|
|
46
49
|
import { useNavigationHelpers } from './useNavigationHelpers';
|
|
@@ -57,7 +60,7 @@ PrivateValueStore;
|
|
|
57
60
|
|
|
58
61
|
type NavigatorRoute = {
|
|
59
62
|
key: string;
|
|
60
|
-
params?: NavigatorScreenParams<ParamListBase
|
|
63
|
+
params?: NavigatorScreenParams<ParamListBase> | undefined;
|
|
61
64
|
};
|
|
62
65
|
|
|
63
66
|
const isScreen = (
|
|
@@ -319,9 +322,14 @@ export function useNavigationBuilder<
|
|
|
319
322
|
) {
|
|
320
323
|
const navigatorKey = useRegisterNavigator();
|
|
321
324
|
|
|
322
|
-
const route = React.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
+
const route = React.use(NavigationRouteContext) as NavigatorRoute | undefined;
|
|
326
|
+
|
|
327
|
+
const consumedParams = React.use(ConsumedParamsContext);
|
|
328
|
+
|
|
329
|
+
const isNestedParamsConsumed =
|
|
330
|
+
typeof route?.params === 'object' && route.params != null
|
|
331
|
+
? consumedParams?.isConsumed(route.params)
|
|
332
|
+
: false;
|
|
325
333
|
|
|
326
334
|
const {
|
|
327
335
|
children,
|
|
@@ -417,7 +425,9 @@ export function useNavigationBuilder<
|
|
|
417
425
|
);
|
|
418
426
|
|
|
419
427
|
const isStateInitialized = React.useCallback(
|
|
420
|
-
|
|
428
|
+
<T extends NavigationState>(
|
|
429
|
+
state: T | PartialState<T> | undefined
|
|
430
|
+
): state is T =>
|
|
421
431
|
state !== undefined && state.stale === false && isStateValid(state),
|
|
422
432
|
[isStateValid]
|
|
423
433
|
);
|
|
@@ -435,16 +445,22 @@ export function useNavigationBuilder<
|
|
|
435
445
|
setKey,
|
|
436
446
|
getKey,
|
|
437
447
|
getIsInitial,
|
|
438
|
-
} = React.
|
|
448
|
+
} = React.use(NavigationStateContext);
|
|
439
449
|
|
|
440
|
-
const
|
|
450
|
+
const stateCleanupRef = React.useRef<boolean>(false);
|
|
451
|
+
const lastStateRef = React.useRef<State | PartialState<State> | undefined>(
|
|
452
|
+
undefined
|
|
453
|
+
);
|
|
441
454
|
|
|
442
455
|
const setState = useLatestCallback(
|
|
443
|
-
(state:
|
|
444
|
-
if (
|
|
456
|
+
(state: State | PartialState<State> | undefined) => {
|
|
457
|
+
if (stateCleanupRef.current) {
|
|
458
|
+
// Store the state locally in case the current navigator is in `Activity`
|
|
459
|
+
lastStateRef.current = state;
|
|
460
|
+
|
|
445
461
|
// State might have been already cleaned up due to unmount
|
|
446
|
-
// We
|
|
447
|
-
//
|
|
462
|
+
// We don't want to update `route.state` in parent
|
|
463
|
+
// Otherwise it will be reused if a new navigator gets mounted
|
|
448
464
|
return;
|
|
449
465
|
}
|
|
450
466
|
|
|
@@ -456,11 +472,32 @@ export function useNavigationBuilder<
|
|
|
456
472
|
stateBeforeInitialization,
|
|
457
473
|
initializedState,
|
|
458
474
|
isFirstStateInitialization,
|
|
475
|
+
paramsUsedForInitialization,
|
|
459
476
|
] = React.useMemo((): [
|
|
460
477
|
PartialState<State> | undefined,
|
|
461
478
|
State | undefined,
|
|
462
479
|
boolean,
|
|
480
|
+
object | undefined,
|
|
463
481
|
] => {
|
|
482
|
+
// If the state was already cleaned up, but we have it stored in ref,
|
|
483
|
+
// It likely got cleaned up due to `<Activity mode="hidden">`
|
|
484
|
+
// We should reuse this state to avoid remounting screens
|
|
485
|
+
if (
|
|
486
|
+
stateCleanupRef.current &&
|
|
487
|
+
lastStateRef.current &&
|
|
488
|
+
isStateValid(lastStateRef.current)
|
|
489
|
+
) {
|
|
490
|
+
const state: State = isStateInitialized(lastStateRef.current)
|
|
491
|
+
? lastStateRef.current
|
|
492
|
+
: router.getRehydratedState(lastStateRef.current, {
|
|
493
|
+
routeNames,
|
|
494
|
+
routeParamList,
|
|
495
|
+
routeGetIdList,
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
return [undefined, state, false, undefined];
|
|
499
|
+
}
|
|
500
|
+
|
|
464
501
|
const initialRouteParamList = routeNames.reduce<
|
|
465
502
|
Record<string, object | undefined>
|
|
466
503
|
>((acc, curr) => {
|
|
@@ -493,7 +530,8 @@ export function useNavigationBuilder<
|
|
|
493
530
|
!(
|
|
494
531
|
typeof route?.params?.screen === 'string' &&
|
|
495
532
|
route?.params?.initial !== false
|
|
496
|
-
)
|
|
533
|
+
) &&
|
|
534
|
+
!isNestedParamsConsumed
|
|
497
535
|
) {
|
|
498
536
|
return [
|
|
499
537
|
undefined,
|
|
@@ -503,28 +541,40 @@ export function useNavigationBuilder<
|
|
|
503
541
|
routeGetIdList,
|
|
504
542
|
}),
|
|
505
543
|
true,
|
|
544
|
+
undefined,
|
|
506
545
|
];
|
|
507
546
|
} else {
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
547
|
+
const paramsForState = isNestedParamsConsumed ? undefined : route?.params;
|
|
548
|
+
const stateFromParams = paramsForState
|
|
549
|
+
? getStateFromParams(paramsForState)
|
|
550
|
+
: undefined;
|
|
551
|
+
|
|
552
|
+
const stateBeforeInitialization = (stateFromParams ?? currentState) as
|
|
553
|
+
| PartialState<State>
|
|
554
|
+
| undefined;
|
|
555
|
+
|
|
556
|
+
const hydratedState =
|
|
557
|
+
stateBeforeInitialization == null
|
|
558
|
+
? router.getInitialState({
|
|
559
|
+
routeNames,
|
|
560
|
+
routeParamList: initialRouteParamList,
|
|
561
|
+
routeGetIdList,
|
|
562
|
+
})
|
|
563
|
+
: router.getRehydratedState(stateBeforeInitialization, {
|
|
564
|
+
routeNames,
|
|
565
|
+
routeParamList: initialRouteParamList,
|
|
566
|
+
routeGetIdList,
|
|
567
|
+
});
|
|
519
568
|
|
|
520
569
|
if (
|
|
570
|
+
stateBeforeInitialization != null &&
|
|
521
571
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
522
572
|
doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)
|
|
523
573
|
) {
|
|
524
|
-
return [stateBeforeInitialization, hydratedState, true];
|
|
574
|
+
return [stateBeforeInitialization, hydratedState, true, paramsForState];
|
|
525
575
|
}
|
|
526
576
|
|
|
527
|
-
return [undefined, hydratedState, false];
|
|
577
|
+
return [undefined, hydratedState, false, paramsForState];
|
|
528
578
|
}
|
|
529
579
|
// We explicitly don't include routeNames, route.params etc. in the dep list
|
|
530
580
|
// below. We want to avoid forcing a new state to be calculated in those cases
|
|
@@ -602,22 +652,18 @@ export function useNavigationBuilder<
|
|
|
602
652
|
});
|
|
603
653
|
}
|
|
604
654
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
React.useEffect(() => {
|
|
608
|
-
previousNestedParamsRef.current = route?.params;
|
|
609
|
-
}, [route?.params]);
|
|
610
|
-
|
|
611
|
-
if (route?.params) {
|
|
612
|
-
const previousParams = previousNestedParamsRef.current;
|
|
655
|
+
let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
|
|
613
656
|
|
|
657
|
+
if (route?.params && !didConsumeNestedParams) {
|
|
614
658
|
let action: CommonActions.Action | undefined;
|
|
615
659
|
|
|
616
660
|
if (
|
|
617
661
|
typeof route.params.state === 'object' &&
|
|
618
662
|
route.params.state != null &&
|
|
619
|
-
|
|
663
|
+
!isNestedParamsConsumed
|
|
620
664
|
) {
|
|
665
|
+
didConsumeNestedParams = true;
|
|
666
|
+
|
|
621
667
|
if (
|
|
622
668
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
623
669
|
doesStateHaveOnlyInvalidRoutes(route.params.state)
|
|
@@ -632,8 +678,10 @@ export function useNavigationBuilder<
|
|
|
632
678
|
} else if (
|
|
633
679
|
typeof route.params.screen === 'string' &&
|
|
634
680
|
((route.params.initial === false && isFirstStateInitialization) ||
|
|
635
|
-
|
|
681
|
+
!isNestedParamsConsumed)
|
|
636
682
|
) {
|
|
683
|
+
didConsumeNestedParams = true;
|
|
684
|
+
|
|
637
685
|
if (
|
|
638
686
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
639
687
|
!routeNames.includes(route.params.screen)
|
|
@@ -674,14 +722,24 @@ export function useNavigationBuilder<
|
|
|
674
722
|
: nextState;
|
|
675
723
|
}
|
|
676
724
|
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
725
|
+
const setConsumedParams = consumedParams?.setConsumed;
|
|
726
|
+
|
|
727
|
+
React.useEffect(() => {
|
|
728
|
+
if (
|
|
729
|
+
setConsumedParams &&
|
|
730
|
+
didConsumeNestedParams &&
|
|
731
|
+
typeof route?.params === 'object' &&
|
|
732
|
+
route.params != null
|
|
733
|
+
) {
|
|
734
|
+
setConsumedParams(route.params);
|
|
735
|
+
}
|
|
736
|
+
}, [didConsumeNestedParams, route?.params, setConsumedParams]);
|
|
737
|
+
|
|
738
|
+
const shouldUpdate = state !== nextState;
|
|
681
739
|
|
|
682
740
|
useScheduleUpdate(() => {
|
|
683
741
|
if (shouldUpdate) {
|
|
684
|
-
//
|
|
742
|
+
// Schedule an update if the state needs to be updated
|
|
685
743
|
setState(nextState);
|
|
686
744
|
|
|
687
745
|
if (shouldClearUnhandledState) {
|
|
@@ -695,25 +753,35 @@ export function useNavigationBuilder<
|
|
|
695
753
|
// So we override the state object we return to use the latest state as soon as possible
|
|
696
754
|
state = nextState;
|
|
697
755
|
|
|
756
|
+
// Last state to reuse if component gets cleaned up due to `<Activity mode="hidden">`
|
|
757
|
+
React.useEffect(() => {
|
|
758
|
+
lastStateRef.current = state;
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
const lastNotifiedStateRef = React.useRef<State | null>(null);
|
|
762
|
+
|
|
698
763
|
React.useEffect(() => {
|
|
699
764
|
// In strict mode, React will double-invoke effects.
|
|
700
765
|
// So we need to reset the flag if component was not unmounted
|
|
701
|
-
|
|
766
|
+
stateCleanupRef.current = false;
|
|
702
767
|
|
|
703
768
|
setKey(navigatorKey);
|
|
704
769
|
|
|
705
|
-
if (!getIsInitial()) {
|
|
770
|
+
if (!getIsInitial() && lastNotifiedStateRef.current !== state) {
|
|
706
771
|
// If it's not initial render, we need to update the state
|
|
707
772
|
// This will make sure that our container gets notifier of state changes due to new mounts
|
|
708
773
|
// This is necessary for proper screen tracking, URL updates etc.
|
|
709
|
-
|
|
774
|
+
// We only notify if the state is different what we already notified
|
|
775
|
+
// Otherwise this goes into a loop when inside `<Activity mode="hidden">`
|
|
776
|
+
setState(state);
|
|
777
|
+
lastNotifiedStateRef.current = state;
|
|
710
778
|
}
|
|
711
779
|
|
|
712
780
|
return () => {
|
|
713
781
|
// We need to clean up state for this navigator on unmount
|
|
714
782
|
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
|
715
783
|
setCurrentState(undefined);
|
|
716
|
-
|
|
784
|
+
stateCleanupRef.current = true;
|
|
717
785
|
}
|
|
718
786
|
};
|
|
719
787
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -742,6 +810,8 @@ export function useNavigationBuilder<
|
|
|
742
810
|
);
|
|
743
811
|
});
|
|
744
812
|
|
|
813
|
+
const { onEmitEvent } = React.use(NavigationBuilderContext);
|
|
814
|
+
|
|
745
815
|
const emitter = useEventEmitter<EventMapCore<State>>((e) => {
|
|
746
816
|
const routeNames = [];
|
|
747
817
|
|
|
@@ -793,6 +863,13 @@ export function useNavigationBuilder<
|
|
|
793
863
|
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
|
794
864
|
|
|
795
865
|
listeners.forEach((listener) => listener?.(e));
|
|
866
|
+
|
|
867
|
+
onEmitEvent({
|
|
868
|
+
type: e.type,
|
|
869
|
+
data: e.data,
|
|
870
|
+
target: e.target,
|
|
871
|
+
defaultPrevented: e.defaultPrevented,
|
|
872
|
+
});
|
|
796
873
|
});
|
|
797
874
|
|
|
798
875
|
useFocusEvents({ state, emitter });
|
|
@@ -827,7 +904,7 @@ export function useNavigationBuilder<
|
|
|
827
904
|
setState,
|
|
828
905
|
});
|
|
829
906
|
|
|
830
|
-
const onUnhandledActionParent = React.
|
|
907
|
+
const onUnhandledActionParent = React.use(UnhandledActionContext);
|
|
831
908
|
|
|
832
909
|
const onUnhandledAction = useLatestCallback((action: NavigationAction) => {
|
|
833
910
|
if (
|
|
@@ -887,13 +964,15 @@ export function useNavigationBuilder<
|
|
|
887
964
|
getStateListeners: keyedListeners.getState,
|
|
888
965
|
});
|
|
889
966
|
|
|
890
|
-
const
|
|
967
|
+
const descriptors = useDescriptors<
|
|
891
968
|
State,
|
|
892
969
|
ActionHelpers,
|
|
893
970
|
ScreenOptions,
|
|
894
971
|
EventMap
|
|
895
972
|
>({
|
|
896
|
-
|
|
973
|
+
routes: router.getRoutesFromState
|
|
974
|
+
? router.getRoutesFromState(state)
|
|
975
|
+
: state.routes,
|
|
897
976
|
screens,
|
|
898
977
|
navigation,
|
|
899
978
|
screenOptions,
|
|
@@ -930,7 +1009,11 @@ export function useNavigationBuilder<
|
|
|
930
1009
|
<NavigationMetaContext.Provider value={undefined}>
|
|
931
1010
|
<NavigationHelpersContext.Provider value={navigation}>
|
|
932
1011
|
<NavigationStateListenerProvider state={state}>
|
|
933
|
-
<
|
|
1012
|
+
<FocusedRouteKeyContext.Provider
|
|
1013
|
+
value={state.routes[state.index].key}
|
|
1014
|
+
>
|
|
1015
|
+
<PreventRemoveProvider>{element}</PreventRemoveProvider>
|
|
1016
|
+
</FocusedRouteKeyContext.Provider>
|
|
934
1017
|
</NavigationStateListenerProvider>
|
|
935
1018
|
</NavigationHelpersContext.Provider>
|
|
936
1019
|
</NavigationMetaContext.Provider>
|
|
@@ -940,7 +1023,6 @@ export function useNavigationBuilder<
|
|
|
940
1023
|
return {
|
|
941
1024
|
state,
|
|
942
1025
|
navigation,
|
|
943
|
-
describe,
|
|
944
1026
|
descriptors,
|
|
945
1027
|
NavigationContent,
|
|
946
1028
|
};
|