@react-navigation/core 8.0.0-alpha.0 → 8.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/NavigationMetaContext.js +15 -0
- package/lib/module/NavigationMetaContext.js.map +1 -0
- 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 +30 -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 +2 -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 +92 -42
- 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/NavigationMetaContext.d.ts +12 -0
- package/lib/typescript/src/NavigationMetaContext.d.ts.map +1 -0
- 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 +33 -19
- 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 +3 -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 +35 -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/NavigationMetaContext.tsx +14 -0
- 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 +100 -30
- 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 +2 -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 +138 -53
- 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 +72 -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,11 +15,14 @@ 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';
|
|
25
|
+
import { NavigationMetaContext } from './NavigationMetaContext';
|
|
23
26
|
import { NavigationRouteContext } from './NavigationProvider';
|
|
24
27
|
import { NavigationStateContext } from './NavigationStateContext';
|
|
25
28
|
import { PreventRemoveProvider } from './PreventRemoveProvider';
|
|
@@ -40,6 +43,7 @@ import { type ScreenConfigWithParent, useDescriptors } from './useDescriptors';
|
|
|
40
43
|
import { useEventEmitter } from './useEventEmitter';
|
|
41
44
|
import { useFocusedListenersChildrenAdapter } from './useFocusedListenersChildrenAdapter';
|
|
42
45
|
import { useFocusEvents } from './useFocusEvents';
|
|
46
|
+
import { FocusedRouteKeyContext } from './useIsFocused';
|
|
43
47
|
import { useKeyedChildListeners } from './useKeyedChildListeners';
|
|
44
48
|
import { useLazyValue } from './useLazyValue';
|
|
45
49
|
import { useNavigationHelpers } from './useNavigationHelpers';
|
|
@@ -56,7 +60,7 @@ PrivateValueStore;
|
|
|
56
60
|
|
|
57
61
|
type NavigatorRoute = {
|
|
58
62
|
key: string;
|
|
59
|
-
params?: NavigatorScreenParams<ParamListBase
|
|
63
|
+
params?: NavigatorScreenParams<ParamListBase> | undefined;
|
|
60
64
|
};
|
|
61
65
|
|
|
62
66
|
const isScreen = (
|
|
@@ -318,9 +322,14 @@ export function useNavigationBuilder<
|
|
|
318
322
|
) {
|
|
319
323
|
const navigatorKey = useRegisterNavigator();
|
|
320
324
|
|
|
321
|
-
const route = React.
|
|
322
|
-
|
|
323
|
-
|
|
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;
|
|
324
333
|
|
|
325
334
|
const {
|
|
326
335
|
children,
|
|
@@ -416,7 +425,9 @@ export function useNavigationBuilder<
|
|
|
416
425
|
);
|
|
417
426
|
|
|
418
427
|
const isStateInitialized = React.useCallback(
|
|
419
|
-
|
|
428
|
+
<T extends NavigationState>(
|
|
429
|
+
state: T | PartialState<T> | undefined
|
|
430
|
+
): state is T =>
|
|
420
431
|
state !== undefined && state.stale === false && isStateValid(state),
|
|
421
432
|
[isStateValid]
|
|
422
433
|
);
|
|
@@ -434,16 +445,22 @@ export function useNavigationBuilder<
|
|
|
434
445
|
setKey,
|
|
435
446
|
getKey,
|
|
436
447
|
getIsInitial,
|
|
437
|
-
} = React.
|
|
448
|
+
} = React.use(NavigationStateContext);
|
|
438
449
|
|
|
439
|
-
const
|
|
450
|
+
const stateCleanupRef = React.useRef<boolean>(false);
|
|
451
|
+
const lastStateRef = React.useRef<State | PartialState<State> | undefined>(
|
|
452
|
+
undefined
|
|
453
|
+
);
|
|
440
454
|
|
|
441
455
|
const setState = useLatestCallback(
|
|
442
|
-
(state:
|
|
443
|
-
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
|
+
|
|
444
461
|
// State might have been already cleaned up due to unmount
|
|
445
|
-
// We
|
|
446
|
-
//
|
|
462
|
+
// We don't want to update `route.state` in parent
|
|
463
|
+
// Otherwise it will be reused if a new navigator gets mounted
|
|
447
464
|
return;
|
|
448
465
|
}
|
|
449
466
|
|
|
@@ -455,11 +472,32 @@ export function useNavigationBuilder<
|
|
|
455
472
|
stateBeforeInitialization,
|
|
456
473
|
initializedState,
|
|
457
474
|
isFirstStateInitialization,
|
|
475
|
+
paramsUsedForInitialization,
|
|
458
476
|
] = React.useMemo((): [
|
|
459
477
|
PartialState<State> | undefined,
|
|
460
478
|
State | undefined,
|
|
461
479
|
boolean,
|
|
480
|
+
object | undefined,
|
|
462
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
|
+
|
|
463
501
|
const initialRouteParamList = routeNames.reduce<
|
|
464
502
|
Record<string, object | undefined>
|
|
465
503
|
>((acc, curr) => {
|
|
@@ -492,7 +530,8 @@ export function useNavigationBuilder<
|
|
|
492
530
|
!(
|
|
493
531
|
typeof route?.params?.screen === 'string' &&
|
|
494
532
|
route?.params?.initial !== false
|
|
495
|
-
)
|
|
533
|
+
) &&
|
|
534
|
+
!isNestedParamsConsumed
|
|
496
535
|
) {
|
|
497
536
|
return [
|
|
498
537
|
undefined,
|
|
@@ -502,28 +541,40 @@ export function useNavigationBuilder<
|
|
|
502
541
|
routeGetIdList,
|
|
503
542
|
}),
|
|
504
543
|
true,
|
|
544
|
+
undefined,
|
|
505
545
|
];
|
|
506
546
|
} else {
|
|
507
|
-
const
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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
|
+
});
|
|
518
568
|
|
|
519
569
|
if (
|
|
570
|
+
stateBeforeInitialization != null &&
|
|
520
571
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
521
572
|
doesStateHaveOnlyInvalidRoutes(stateBeforeInitialization)
|
|
522
573
|
) {
|
|
523
|
-
return [stateBeforeInitialization, hydratedState, true];
|
|
574
|
+
return [stateBeforeInitialization, hydratedState, true, paramsForState];
|
|
524
575
|
}
|
|
525
576
|
|
|
526
|
-
return [undefined, hydratedState, false];
|
|
577
|
+
return [undefined, hydratedState, false, paramsForState];
|
|
527
578
|
}
|
|
528
579
|
// We explicitly don't include routeNames, route.params etc. in the dep list
|
|
529
580
|
// below. We want to avoid forcing a new state to be calculated in those cases
|
|
@@ -601,22 +652,18 @@ export function useNavigationBuilder<
|
|
|
601
652
|
});
|
|
602
653
|
}
|
|
603
654
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
React.useEffect(() => {
|
|
607
|
-
previousNestedParamsRef.current = route?.params;
|
|
608
|
-
}, [route?.params]);
|
|
609
|
-
|
|
610
|
-
if (route?.params) {
|
|
611
|
-
const previousParams = previousNestedParamsRef.current;
|
|
655
|
+
let didConsumeNestedParams = route?.params === paramsUsedForInitialization;
|
|
612
656
|
|
|
657
|
+
if (route?.params && !didConsumeNestedParams) {
|
|
613
658
|
let action: CommonActions.Action | undefined;
|
|
614
659
|
|
|
615
660
|
if (
|
|
616
661
|
typeof route.params.state === 'object' &&
|
|
617
662
|
route.params.state != null &&
|
|
618
|
-
|
|
663
|
+
!isNestedParamsConsumed
|
|
619
664
|
) {
|
|
665
|
+
didConsumeNestedParams = true;
|
|
666
|
+
|
|
620
667
|
if (
|
|
621
668
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
622
669
|
doesStateHaveOnlyInvalidRoutes(route.params.state)
|
|
@@ -631,8 +678,10 @@ export function useNavigationBuilder<
|
|
|
631
678
|
} else if (
|
|
632
679
|
typeof route.params.screen === 'string' &&
|
|
633
680
|
((route.params.initial === false && isFirstStateInitialization) ||
|
|
634
|
-
|
|
681
|
+
!isNestedParamsConsumed)
|
|
635
682
|
) {
|
|
683
|
+
didConsumeNestedParams = true;
|
|
684
|
+
|
|
636
685
|
if (
|
|
637
686
|
options.routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
638
687
|
!routeNames.includes(route.params.screen)
|
|
@@ -673,14 +722,24 @@ export function useNavigationBuilder<
|
|
|
673
722
|
: nextState;
|
|
674
723
|
}
|
|
675
724
|
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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;
|
|
680
739
|
|
|
681
740
|
useScheduleUpdate(() => {
|
|
682
741
|
if (shouldUpdate) {
|
|
683
|
-
//
|
|
742
|
+
// Schedule an update if the state needs to be updated
|
|
684
743
|
setState(nextState);
|
|
685
744
|
|
|
686
745
|
if (shouldClearUnhandledState) {
|
|
@@ -694,25 +753,35 @@ export function useNavigationBuilder<
|
|
|
694
753
|
// So we override the state object we return to use the latest state as soon as possible
|
|
695
754
|
state = nextState;
|
|
696
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
|
+
|
|
697
763
|
React.useEffect(() => {
|
|
698
764
|
// In strict mode, React will double-invoke effects.
|
|
699
765
|
// So we need to reset the flag if component was not unmounted
|
|
700
|
-
|
|
766
|
+
stateCleanupRef.current = false;
|
|
701
767
|
|
|
702
768
|
setKey(navigatorKey);
|
|
703
769
|
|
|
704
|
-
if (!getIsInitial()) {
|
|
770
|
+
if (!getIsInitial() && lastNotifiedStateRef.current !== state) {
|
|
705
771
|
// If it's not initial render, we need to update the state
|
|
706
772
|
// This will make sure that our container gets notifier of state changes due to new mounts
|
|
707
773
|
// This is necessary for proper screen tracking, URL updates etc.
|
|
708
|
-
|
|
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;
|
|
709
778
|
}
|
|
710
779
|
|
|
711
780
|
return () => {
|
|
712
781
|
// We need to clean up state for this navigator on unmount
|
|
713
782
|
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
|
714
783
|
setCurrentState(undefined);
|
|
715
|
-
|
|
784
|
+
stateCleanupRef.current = true;
|
|
716
785
|
}
|
|
717
786
|
};
|
|
718
787
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -741,6 +810,8 @@ export function useNavigationBuilder<
|
|
|
741
810
|
);
|
|
742
811
|
});
|
|
743
812
|
|
|
813
|
+
const { onEmitEvent } = React.use(NavigationBuilderContext);
|
|
814
|
+
|
|
744
815
|
const emitter = useEventEmitter<EventMapCore<State>>((e) => {
|
|
745
816
|
const routeNames = [];
|
|
746
817
|
|
|
@@ -792,6 +863,13 @@ export function useNavigationBuilder<
|
|
|
792
863
|
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
|
793
864
|
|
|
794
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
|
+
});
|
|
795
873
|
});
|
|
796
874
|
|
|
797
875
|
useFocusEvents({ state, emitter });
|
|
@@ -826,7 +904,7 @@ export function useNavigationBuilder<
|
|
|
826
904
|
setState,
|
|
827
905
|
});
|
|
828
906
|
|
|
829
|
-
const onUnhandledActionParent = React.
|
|
907
|
+
const onUnhandledActionParent = React.use(UnhandledActionContext);
|
|
830
908
|
|
|
831
909
|
const onUnhandledAction = useLatestCallback((action: NavigationAction) => {
|
|
832
910
|
if (
|
|
@@ -886,13 +964,15 @@ export function useNavigationBuilder<
|
|
|
886
964
|
getStateListeners: keyedListeners.getState,
|
|
887
965
|
});
|
|
888
966
|
|
|
889
|
-
const
|
|
967
|
+
const descriptors = useDescriptors<
|
|
890
968
|
State,
|
|
891
969
|
ActionHelpers,
|
|
892
970
|
ScreenOptions,
|
|
893
971
|
EventMap
|
|
894
972
|
>({
|
|
895
|
-
|
|
973
|
+
routes: router.getRoutesFromState
|
|
974
|
+
? router.getRoutesFromState(state)
|
|
975
|
+
: state.routes,
|
|
896
976
|
screens,
|
|
897
977
|
navigation,
|
|
898
978
|
screenOptions,
|
|
@@ -926,18 +1006,23 @@ export function useNavigationBuilder<
|
|
|
926
1006
|
: children;
|
|
927
1007
|
|
|
928
1008
|
return (
|
|
929
|
-
<
|
|
930
|
-
<
|
|
931
|
-
<
|
|
932
|
-
|
|
933
|
-
|
|
1009
|
+
<NavigationMetaContext.Provider value={undefined}>
|
|
1010
|
+
<NavigationHelpersContext.Provider value={navigation}>
|
|
1011
|
+
<NavigationStateListenerProvider state={state}>
|
|
1012
|
+
<FocusedRouteKeyContext.Provider
|
|
1013
|
+
value={state.routes[state.index].key}
|
|
1014
|
+
>
|
|
1015
|
+
<PreventRemoveProvider>{element}</PreventRemoveProvider>
|
|
1016
|
+
</FocusedRouteKeyContext.Provider>
|
|
1017
|
+
</NavigationStateListenerProvider>
|
|
1018
|
+
</NavigationHelpersContext.Provider>
|
|
1019
|
+
</NavigationMetaContext.Provider>
|
|
934
1020
|
);
|
|
935
1021
|
});
|
|
936
1022
|
|
|
937
1023
|
return {
|
|
938
1024
|
state,
|
|
939
1025
|
navigation,
|
|
940
|
-
describe,
|
|
941
1026
|
descriptors,
|
|
942
1027
|
NavigationContent,
|
|
943
1028
|
};
|