@react-navigation/core 8.0.0-alpha.3 → 8.0.0-alpha.30
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 +34 -17
- 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/DataLoading.js +127 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js +1 -0
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +17 -8
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +22 -11
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/PreventRemoveContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +37 -27
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/SceneView.js +7 -40
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +179 -50
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/StaticTreeContext.js +5 -0
- package/lib/module/StaticTreeContext.js.map +1 -0
- package/lib/module/checkSerializable.js +18 -13
- package/lib/module/checkSerializable.js.map +1 -1
- package/lib/module/createNavigationContainerRef.js +6 -8
- package/lib/module/createNavigationContainerRef.js.map +1 -1
- package/lib/module/createNavigatorFactory.js +27 -5
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/findFocusedRoute.js +7 -4
- package/lib/module/findFocusedRoute.js.map +1 -1
- package/lib/module/getActionFromState.js +45 -20
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getPathFromState.js +171 -90
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +20 -4
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +485 -214
- 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 +5 -4
- 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 +35 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +19 -11
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useEventEmitter.js +48 -33
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useFocusEvents.js +12 -4
- package/lib/module/useFocusEvents.js.map +1 -1
- package/lib/module/useFocusedListenersChildrenAdapter.js +2 -2
- 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/useKeyedChildListeners.js +4 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useLazyValue.js.map +1 -1
- package/lib/module/useNavigation.js +2 -15
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +201 -131
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +22 -17
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +28 -10
- 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 +70 -35
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +37 -7
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnGetState.js +6 -3
- package/lib/module/useOnGetState.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +39 -30
- 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 +10 -5
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +10 -3
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/usePreventRemoveContext.js +1 -1
- package/lib/module/usePreventRemoveContext.js.map +1 -1
- package/lib/module/useRegisterNavigator.js +2 -2
- package/lib/module/useRegisterNavigator.js.map +1 -1
- package/lib/module/useRoute.js +2 -0
- package/lib/module/useRoute.js.map +1 -1
- package/lib/module/useRouteCache.js +17 -11
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +9 -9
- 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/module/useSyncState.js +7 -3
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/module/validatePathConfig.js +50 -36
- package/lib/module/validatePathConfig.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 +3 -0
- package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
- package/lib/typescript/src/DataLoading.d.ts +21 -0
- package/lib/typescript/src/DataLoading.d.ts.map +1 -0
- package/lib/typescript/src/EnsureSingleNavigator.d.ts +1 -1
- package/lib/typescript/src/EnsureSingleNavigator.d.ts.map +1 -1
- package/lib/typescript/src/Group.d.ts +1 -1
- package/lib/typescript/src/Group.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +9 -8
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.d.ts +1 -1
- package/lib/typescript/src/NavigationContainerRefContext.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/NavigationHelpersContext.d.ts +1 -1
- package/lib/typescript/src/NavigationHelpersContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +12 -13
- 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/PreventRemoveContext.d.ts +1 -0
- package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +3 -2
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/Screen.d.ts +1 -1
- package/lib/typescript/src/Screen.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 +189 -109
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
- package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
- package/lib/typescript/src/checkSerializable.d.ts +8 -4
- package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +23 -5
- 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 +4 -4
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts +3 -3
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPatternParts.d.ts +1 -0
- package/lib/typescript/src/getPatternParts.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +5 -5
- 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 +36 -33
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts +1 -1
- package/lib/typescript/src/theming/ThemeContext.d.ts.map +1 -1
- package/lib/typescript/src/theming/ThemeProvider.d.ts +2 -2
- package/lib/typescript/src/theming/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts +1 -1
- package/lib/typescript/src/theming/useTheme.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +260 -159
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useChildListeners.d.ts +3 -3
- package/lib/typescript/src/useChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useComponent.d.ts +1 -1
- package/lib/typescript/src/useComponent.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +8 -8
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts +2 -2
- package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/useFocusEvents.d.ts +2 -2
- package/lib/typescript/src/useFocusEvents.d.ts.map +1 -1
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +2 -2
- package/lib/typescript/src/useFocusedListenersChildrenAdapter.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/useKeyedChildListeners.d.ts +3 -3
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useLazyValue.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts +4 -2
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +23 -30
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts +3 -3
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts +1 -1
- package/lib/typescript/src/useNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +19 -27
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +13 -3
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts +9 -9
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnGetState.d.ts +1 -1
- package/lib/typescript/src/useOnGetState.d.ts.map +1 -1
- package/lib/typescript/src/useOnPreventRemove.d.ts +5 -9
- package/lib/typescript/src/useOnPreventRemove.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/useOptionsGetters.d.ts +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts +2 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/useRoute.d.ts +7 -3
- package/lib/typescript/src/useRoute.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts +5 -5
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/useStateForPath.d.ts +1 -1
- package/lib/typescript/src/useStateForPath.d.ts.map +1 -1
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +74 -37
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +23 -22
- package/src/BaseNavigationContainer.tsx +351 -333
- package/src/ConsumedParamsContext.tsx +5 -0
- package/src/DataLoading.tsx +203 -0
- package/src/NavigationBuilderContext.tsx +14 -9
- package/src/NavigationFocusedRouteStateContext.tsx +4 -4
- package/src/NavigationIndependentTree.tsx +18 -12
- package/src/NavigationProvider.tsx +26 -15
- package/src/NavigationStateContext.tsx +5 -6
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +51 -46
- package/src/SceneView.tsx +7 -39
- package/src/StaticNavigation.tsx +659 -307
- package/src/StaticTreeContext.tsx +7 -0
- package/src/checkSerializable.tsx +35 -19
- package/src/createNavigationContainerRef.tsx +12 -9
- package/src/createNavigatorFactory.tsx +92 -8
- package/src/findFocusedRoute.tsx +13 -8
- package/src/getActionFromState.tsx +86 -51
- package/src/getPathFromState.tsx +254 -128
- package/src/getPatternParts.tsx +25 -4
- package/src/getStateFromPath.tsx +811 -309
- package/src/getStateFromRouteParams.tsx +60 -0
- package/src/index.tsx +55 -5
- package/src/theming/useTheme.tsx +1 -1
- package/src/types.tsx +798 -373
- package/src/useDescriptors.tsx +28 -14
- package/src/useEventEmitter.tsx +52 -38
- package/src/useFocusEvents.tsx +15 -7
- package/src/useFocusedListenersChildrenAdapter.tsx +2 -2
- package/src/useIsFocused.tsx +14 -21
- package/src/useKeyedChildListeners.tsx +4 -2
- package/src/useLazyValue.tsx +2 -2
- package/src/useNavigation.tsx +7 -24
- package/src/useNavigationBuilder.tsx +311 -186
- package/src/useNavigationCache.tsx +32 -25
- package/src/useNavigationHelpers.tsx +27 -10
- package/src/useNavigationIndependentTree.tsx +1 -1
- package/src/useNavigationState.tsx +93 -59
- package/src/useOnAction.tsx +61 -13
- package/src/useOnGetState.tsx +5 -3
- package/src/useOnPreventRemove.tsx +75 -42
- package/src/useOnRouteFocus.tsx +10 -12
- package/src/useOptionsGetters.tsx +11 -5
- package/src/usePreventRemove.tsx +12 -3
- package/src/usePreventRemoveContext.tsx +1 -1
- package/src/useRegisterNavigator.tsx +2 -2
- package/src/useRoute.tsx +20 -6
- package/src/useRouteCache.tsx +22 -16
- package/src/useScheduleUpdate.tsx +9 -10
- package/src/useStateForPath.tsx +1 -1
- package/src/useSyncState.tsx +8 -3
- package/src/utilities.tsx +144 -31
- package/src/validatePathConfig.tsx +86 -57
- package/lib/module/CurrentRenderContext.js +0 -10
- package/lib/module/CurrentRenderContext.js.map +0 -1
- package/lib/module/useCurrentRender.js +0 -19
- package/lib/module/useCurrentRender.js.map +0 -1
- package/lib/typescript/src/CurrentRenderContext.d.ts +0 -9
- package/lib/typescript/src/CurrentRenderContext.d.ts.map +0 -1
- package/lib/typescript/src/useCurrentRender.d.ts +0 -14
- package/lib/typescript/src/useCurrentRender.d.ts.map +0 -1
- package/src/CurrentRenderContext.tsx +0 -9
- package/src/useCurrentRender.tsx +0 -31
|
@@ -23,8 +23,8 @@ type Options<
|
|
|
23
23
|
Partial<NavigationProp<ParamListBase, string, any, any, any>>;
|
|
24
24
|
setOptions: (
|
|
25
25
|
cb: (
|
|
26
|
-
options: Record<string, ScreenOptions>
|
|
27
|
-
) => Record<string, ScreenOptions>
|
|
26
|
+
options: Record<string, Partial<ScreenOptions> | undefined>
|
|
27
|
+
) => Record<string, Partial<ScreenOptions> | undefined>
|
|
28
28
|
) => void;
|
|
29
29
|
router: Router<State, NavigationAction>;
|
|
30
30
|
emitter: NavigationEventEmitter<EventMap>;
|
|
@@ -72,8 +72,8 @@ export function useNavigationCache<
|
|
|
72
72
|
router,
|
|
73
73
|
emitter,
|
|
74
74
|
}: Options<State, ScreenOptions, EventMap>) {
|
|
75
|
-
const parentNavigationHelpers = React.
|
|
76
|
-
const { stackRef } = React.
|
|
75
|
+
const parentNavigationHelpers = React.use(NavigationContext);
|
|
76
|
+
const { stackRef } = React.use(NavigationBuilderContext);
|
|
77
77
|
|
|
78
78
|
// Cache object which holds navigation objects for each screen
|
|
79
79
|
// We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
|
|
@@ -91,27 +91,15 @@ export function useNavigationCache<
|
|
|
91
91
|
[getState, parentNavigationHelpers, navigation, setOptions, emitter]
|
|
92
92
|
);
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
const next = routes.reduce<
|
|
95
95
|
NavigationCache<State, ScreenOptions, EventMap, ActionHelpers>
|
|
96
96
|
>((acc, route) => {
|
|
97
97
|
const previous = cache.current[route.key];
|
|
98
98
|
|
|
99
|
-
type Thunk =
|
|
100
|
-
| NavigationAction
|
|
101
|
-
| ((state: State) => NavigationAction | null | undefined);
|
|
102
|
-
|
|
103
99
|
if (previous) {
|
|
104
100
|
// If a cached navigation object already exists, reuse it
|
|
105
101
|
acc[route.key] = previous;
|
|
106
102
|
} else {
|
|
107
|
-
const dispatch = (thunk: Thunk) => {
|
|
108
|
-
const action = typeof thunk === 'function' ? thunk(getState()) : thunk;
|
|
109
|
-
|
|
110
|
-
if (action != null) {
|
|
111
|
-
navigation.dispatch({ source: route.key, ...action });
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
103
|
const withStack = (callback: () => void) => {
|
|
116
104
|
let isStackSet = false;
|
|
117
105
|
|
|
@@ -134,6 +122,23 @@ export function useNavigationCache<
|
|
|
134
122
|
}
|
|
135
123
|
};
|
|
136
124
|
|
|
125
|
+
const dispatch = (
|
|
126
|
+
thunk:
|
|
127
|
+
| NavigationAction
|
|
128
|
+
| ((state: State) => NavigationAction | null | undefined)
|
|
129
|
+
) => {
|
|
130
|
+
withStack(() =>
|
|
131
|
+
React.startTransition(() => {
|
|
132
|
+
const action =
|
|
133
|
+
typeof thunk === 'function' ? thunk(getState()) : thunk;
|
|
134
|
+
|
|
135
|
+
if (action != null) {
|
|
136
|
+
navigation.dispatch({ source: route.key, ...action });
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
137
142
|
const actions = {
|
|
138
143
|
...router.actionCreators,
|
|
139
144
|
...CommonActions,
|
|
@@ -142,10 +147,8 @@ export function useNavigationCache<
|
|
|
142
147
|
const helpers = Object.keys(actions).reduce<Record<string, () => void>>(
|
|
143
148
|
(acc, name) => {
|
|
144
149
|
acc[name] = (...args: any) =>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
dispatch(actions[name](...args))
|
|
148
|
-
);
|
|
150
|
+
// @ts-expect-error: name is a valid key, but TypeScript is dumb
|
|
151
|
+
dispatch(actions[name](...args));
|
|
149
152
|
|
|
150
153
|
return acc;
|
|
151
154
|
},
|
|
@@ -160,7 +163,7 @@ export function useNavigationCache<
|
|
|
160
163
|
...helpers,
|
|
161
164
|
// FIXME: too much work to fix the types for now
|
|
162
165
|
...(emitter.create(route.key) as any),
|
|
163
|
-
dispatch
|
|
166
|
+
dispatch,
|
|
164
167
|
getParent: (routeName) => {
|
|
165
168
|
if (routeName === route.name) {
|
|
166
169
|
// If the passed route name is the same as the current route's name,
|
|
@@ -174,7 +177,7 @@ export function useNavigationCache<
|
|
|
174
177
|
|
|
175
178
|
return parentNavigationHelpers;
|
|
176
179
|
},
|
|
177
|
-
setOptions: (options:
|
|
180
|
+
setOptions: (options: Partial<ScreenOptions>) => {
|
|
178
181
|
setOptions((o) => ({
|
|
179
182
|
...o,
|
|
180
183
|
[route.key]: { ...o[route.key], ...options },
|
|
@@ -183,7 +186,7 @@ export function useNavigationCache<
|
|
|
183
186
|
isFocused: () => {
|
|
184
187
|
const state = rest.getState();
|
|
185
188
|
|
|
186
|
-
if (state.routes[state.index]
|
|
189
|
+
if (state.routes[state.index]?.key !== route.key) {
|
|
187
190
|
return false;
|
|
188
191
|
}
|
|
189
192
|
|
|
@@ -197,5 +200,9 @@ export function useNavigationCache<
|
|
|
197
200
|
return acc;
|
|
198
201
|
}, {});
|
|
199
202
|
|
|
200
|
-
|
|
203
|
+
React.useInsertionEffect(() => {
|
|
204
|
+
cache.current = next;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
return next;
|
|
201
208
|
}
|
|
@@ -19,9 +19,9 @@ type Options<State extends NavigationState, Action extends NavigationAction> = {
|
|
|
19
19
|
onAction: (action: NavigationAction) => boolean;
|
|
20
20
|
onUnhandledAction: (action: NavigationAction) => void;
|
|
21
21
|
getState: () => State;
|
|
22
|
+
state: State;
|
|
22
23
|
emitter: NavigationEventEmitter<any>;
|
|
23
24
|
router: Router<State, Action>;
|
|
24
|
-
stateRef: React.RefObject<State | null>;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -37,11 +37,28 @@ export function useNavigationHelpers<
|
|
|
37
37
|
onAction,
|
|
38
38
|
onUnhandledAction,
|
|
39
39
|
getState,
|
|
40
|
+
state,
|
|
40
41
|
emitter,
|
|
41
42
|
router,
|
|
42
|
-
stateRef,
|
|
43
43
|
}: Options<State, Action>) {
|
|
44
|
-
const parentNavigationHelpers = React.
|
|
44
|
+
const parentNavigationHelpers = React.use(NavigationContext);
|
|
45
|
+
|
|
46
|
+
// In some cases (e.g. route names change), internal state might have changed
|
|
47
|
+
// But it hasn't been committed yet, so hasn't propagated to any listeners
|
|
48
|
+
// During this time, we need to return the internal state in `getState`
|
|
49
|
+
// Otherwise it can return an inconsistent state during render in children
|
|
50
|
+
// This may affect hooks like `useNavigationState` that need to read the state during render
|
|
51
|
+
// To avoid this, we use a ref for render phase, and immediately clear it on commit
|
|
52
|
+
// The ref won't be cleared if the render is discarded, e.g. when interrupted
|
|
53
|
+
// So we also track the stored state the render was based on
|
|
54
|
+
// Then ignore the ref once the stored state changes due to another dispatch
|
|
55
|
+
const stateRef = React.useRef<{ state: State; base: State } | null>(null);
|
|
56
|
+
|
|
57
|
+
stateRef.current = { state, base: getState() };
|
|
58
|
+
|
|
59
|
+
React.useInsertionEffect(() => {
|
|
60
|
+
stateRef.current = null;
|
|
61
|
+
});
|
|
45
62
|
|
|
46
63
|
return React.useMemo(() => {
|
|
47
64
|
const dispatch = (op: Action | ((state: State) => Action)) => {
|
|
@@ -87,16 +104,16 @@ export function useNavigationHelpers<
|
|
|
87
104
|
);
|
|
88
105
|
},
|
|
89
106
|
getState: (): State => {
|
|
107
|
+
const current = getState();
|
|
108
|
+
const pending = stateRef.current;
|
|
109
|
+
|
|
90
110
|
// FIXME: Workaround for when the state is read during render
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// Apart from `useSyncExternalStore`, `getState` should never be called during render
|
|
95
|
-
if (stateRef.current != null) {
|
|
96
|
-
return stateRef.current;
|
|
111
|
+
// Apart from subscriptions, `getState` should never be called during render
|
|
112
|
+
if (pending != null && pending.base === current) {
|
|
113
|
+
return pending.state;
|
|
97
114
|
}
|
|
98
115
|
|
|
99
|
-
return
|
|
116
|
+
return current;
|
|
100
117
|
},
|
|
101
118
|
} as NavigationHelpers<ParamListBase, EventMap> & ActionHelpers;
|
|
102
119
|
|
|
@@ -3,5 +3,5 @@ import * as React from 'react';
|
|
|
3
3
|
import { NavigationIndependentTreeContext } from './NavigationIndependentTreeContext';
|
|
4
4
|
|
|
5
5
|
export function useNavigationIndependentTree() {
|
|
6
|
-
return React.
|
|
6
|
+
return React.use(NavigationIndependentTreeContext);
|
|
7
7
|
}
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import useLatestCallback from 'use-latest-callback';
|
|
4
|
-
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
|
|
5
4
|
|
|
6
|
-
import type {
|
|
7
|
-
NavigationListForNested,
|
|
8
|
-
NavigationProp,
|
|
9
|
-
RootNavigator,
|
|
10
|
-
} from './types';
|
|
11
|
-
import { useNavigation } from './useNavigation';
|
|
5
|
+
import type { NavigationListForNested, RootNavigator } from './types';
|
|
12
6
|
|
|
13
7
|
type NavigationStateListener = {
|
|
14
8
|
getState: () => NavigationState<ParamListBase>;
|
|
@@ -35,8 +29,8 @@ type NavigationStateForNested<
|
|
|
35
29
|
export function useNavigationState<
|
|
36
30
|
const T,
|
|
37
31
|
const Navigator = RootNavigator,
|
|
38
|
-
const RouteName extends
|
|
39
|
-
keyof NavigationListForNested<Navigator
|
|
32
|
+
const RouteName extends keyof NavigationListForNested<Navigator> =
|
|
33
|
+
keyof NavigationListForNested<Navigator>,
|
|
40
34
|
>(
|
|
41
35
|
routeName: RouteName,
|
|
42
36
|
selector: (state: NavigationStateForNested<Navigator, RouteName>) => T
|
|
@@ -45,81 +39,84 @@ export function useNavigationState<T>(
|
|
|
45
39
|
selector: (state: NavigationState<ParamListBase>) => T
|
|
46
40
|
): T;
|
|
47
41
|
export function useNavigationState(...args: unknown[]): unknown {
|
|
48
|
-
|
|
49
|
-
stateListener: NavigationStateListener | undefined,
|
|
50
|
-
selector;
|
|
42
|
+
const selector = typeof args[0] === 'string' ? args[1] : args[0];
|
|
51
43
|
|
|
52
|
-
if (typeof
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
navigation = useNavigation(args[0]);
|
|
57
|
-
selector = args[1];
|
|
58
|
-
} else {
|
|
59
|
-
selector = args[0];
|
|
44
|
+
if (typeof selector !== 'function') {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`A selector function must be provided (got ${typeof selector}).`
|
|
47
|
+
);
|
|
60
48
|
}
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
// @ts-expect-error: the public overloads guarantee the selector's type, but
|
|
51
|
+
// the `unknown[]` implementation signature can't express it
|
|
52
|
+
const select: (state: NavigationState<ParamListBase>) => unknown = selector;
|
|
53
|
+
|
|
54
|
+
let listener: NavigationStateListener | undefined;
|
|
55
|
+
|
|
56
|
+
if (typeof args[0] === 'string') {
|
|
57
|
+
const name = args[0];
|
|
58
|
+
const listeners = React.use(NamedNavigationStateListenerListContext);
|
|
59
|
+
|
|
60
|
+
listener = listeners?.[name];
|
|
61
|
+
|
|
62
|
+
if (listener == null) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Couldn't find a navigator for the route '${name}' in any of the parent screens. Is your component inside the correct screen?`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
listener = React.use(NavigationStateListenerContext);
|
|
64
69
|
|
|
65
|
-
if (
|
|
70
|
+
if (listener == null) {
|
|
66
71
|
throw new Error(
|
|
67
72
|
"Couldn't get the navigation state. Is your component inside a navigator?"
|
|
68
73
|
);
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
const subscribe =
|
|
73
|
-
(callback: () => void) => {
|
|
74
|
-
if (navigation) {
|
|
75
|
-
return navigation.addListener('state', callback);
|
|
76
|
-
} else if (stateListener) {
|
|
77
|
-
return stateListener.subscribe(callback);
|
|
78
|
-
} else {
|
|
79
|
-
throw new Error(
|
|
80
|
-
"Couldn't subscribe to navigation state changes. This is not expected."
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
[navigation, stateListener]
|
|
85
|
-
);
|
|
77
|
+
const { getState, subscribe } = listener;
|
|
86
78
|
|
|
87
|
-
const
|
|
88
|
-
? navigation.getState
|
|
89
|
-
: stateListener?.getState;
|
|
79
|
+
const [, forceUpdate] = React.useReducer((count: number) => count + 1, 0);
|
|
90
80
|
|
|
91
|
-
|
|
92
|
-
throw new Error("Couldn't get the navigation state. This is not expected.");
|
|
93
|
-
}
|
|
81
|
+
const selected = select(getState());
|
|
94
82
|
|
|
95
|
-
|
|
96
|
-
throw new Error(
|
|
97
|
-
`A selector function must be provided (got ${typeof selector}).`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
83
|
+
const selectionRef = React.useRef({ select, selected });
|
|
100
84
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
getSnapshot,
|
|
105
|
-
// @ts-expect-error we can't infer the type here
|
|
106
|
-
selector
|
|
107
|
-
);
|
|
85
|
+
React.useLayoutEffect(() => {
|
|
86
|
+
selectionRef.current = { select, selected };
|
|
87
|
+
});
|
|
108
88
|
|
|
109
|
-
|
|
89
|
+
React.useEffect(() => {
|
|
90
|
+
const checkForUpdates = () => {
|
|
91
|
+
const selection = selectionRef.current;
|
|
92
|
+
|
|
93
|
+
if (!Object.is(selection.selected, selection.select(getState()))) {
|
|
94
|
+
forceUpdate();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const unsubscribe = subscribe(checkForUpdates);
|
|
99
|
+
|
|
100
|
+
// The state may have changed between the render and the subscription
|
|
101
|
+
checkForUpdates();
|
|
102
|
+
|
|
103
|
+
return unsubscribe;
|
|
104
|
+
}, [getState, subscribe]);
|
|
105
|
+
|
|
106
|
+
return selected;
|
|
110
107
|
}
|
|
111
108
|
|
|
112
109
|
export function NavigationStateListenerProvider({
|
|
113
110
|
state,
|
|
111
|
+
getState,
|
|
114
112
|
children,
|
|
115
113
|
}: {
|
|
116
114
|
state: NavigationState<ParamListBase>;
|
|
115
|
+
getState: () => NavigationState<ParamListBase>;
|
|
117
116
|
children: React.ReactNode;
|
|
118
117
|
}) {
|
|
119
118
|
const listeners = React.useRef<(() => void)[]>([]);
|
|
120
119
|
|
|
121
|
-
const getState = useLatestCallback(() => state);
|
|
122
|
-
|
|
123
120
|
const subscribe = useLatestCallback((callback: () => void) => {
|
|
124
121
|
listeners.current.push(callback);
|
|
125
122
|
|
|
@@ -128,7 +125,8 @@ export function NavigationStateListenerProvider({
|
|
|
128
125
|
};
|
|
129
126
|
});
|
|
130
127
|
|
|
131
|
-
|
|
128
|
+
// Notify subscribers once the new state has committed
|
|
129
|
+
React.useLayoutEffect(() => {
|
|
132
130
|
listeners.current.forEach((callback) => callback());
|
|
133
131
|
}, [state]);
|
|
134
132
|
|
|
@@ -147,6 +145,42 @@ export function NavigationStateListenerProvider({
|
|
|
147
145
|
);
|
|
148
146
|
}
|
|
149
147
|
|
|
148
|
+
export function NamedNavigationStateListenerProvider({
|
|
149
|
+
name,
|
|
150
|
+
children,
|
|
151
|
+
}: {
|
|
152
|
+
name: string;
|
|
153
|
+
children: React.ReactNode;
|
|
154
|
+
}) {
|
|
155
|
+
const listener = React.use(NavigationStateListenerContext);
|
|
156
|
+
|
|
157
|
+
if (listener == null) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
"Couldn't find a navigation state listener. This is likely because the navigator doesn't render its content under 'NavigationContent'."
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const parents = React.use(NamedNavigationStateListenerListContext);
|
|
164
|
+
|
|
165
|
+
const listeners = React.useMemo(
|
|
166
|
+
() => ({
|
|
167
|
+
...parents,
|
|
168
|
+
[name]: listener,
|
|
169
|
+
}),
|
|
170
|
+
[listener, name, parents]
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<NamedNavigationStateListenerListContext.Provider value={listeners}>
|
|
175
|
+
{children}
|
|
176
|
+
</NamedNavigationStateListenerListContext.Provider>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
150
180
|
const NavigationStateListenerContext = React.createContext<
|
|
151
181
|
NavigationStateListener | undefined
|
|
152
182
|
>(undefined);
|
|
183
|
+
|
|
184
|
+
export const NamedNavigationStateListenerListContext = React.createContext<
|
|
185
|
+
Record<string, NavigationStateListener> | undefined
|
|
186
|
+
>(undefined);
|
package/src/useOnAction.tsx
CHANGED
|
@@ -7,20 +7,23 @@ import type {
|
|
|
7
7
|
} from '@react-navigation/routers';
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
|
|
10
|
+
import { ConsumedParamsContext } from './ConsumedParamsContext';
|
|
11
|
+
import { getLoaderForStateChange } from './DataLoading';
|
|
10
12
|
import {
|
|
11
13
|
type ChildActionListener,
|
|
12
14
|
type ChildBeforeRemoveListener,
|
|
13
15
|
NavigationBuilderContext,
|
|
14
16
|
} from './NavigationBuilderContext';
|
|
17
|
+
import { StaticTreeContext } from './StaticTreeContext';
|
|
15
18
|
import type { EventMapCore } from './types';
|
|
16
19
|
import type { NavigationEventEmitter } from './useEventEmitter';
|
|
17
20
|
import { shouldPreventRemove, useOnPreventRemove } from './useOnPreventRemove';
|
|
18
21
|
|
|
19
|
-
type Options = {
|
|
20
|
-
router: Router<
|
|
21
|
-
key?: string;
|
|
22
|
-
getState: () =>
|
|
23
|
-
setState: (state:
|
|
22
|
+
type Options<State extends NavigationState> = {
|
|
23
|
+
router: Router<State, NavigationAction>;
|
|
24
|
+
key?: string | undefined;
|
|
25
|
+
getState: () => State;
|
|
26
|
+
setState: (state: State | PartialState<State>) => void;
|
|
24
27
|
actionListeners: ChildActionListener[];
|
|
25
28
|
beforeRemoveListeners: Record<string, ChildBeforeRemoveListener | undefined>;
|
|
26
29
|
routerConfigOptions: RouterConfigOptions;
|
|
@@ -36,7 +39,7 @@ type Options = {
|
|
|
36
39
|
*
|
|
37
40
|
* When the action handler handles as action, it returns `true`, otherwise `false`.
|
|
38
41
|
*/
|
|
39
|
-
export function useOnAction({
|
|
42
|
+
export function useOnAction<State extends NavigationState>({
|
|
40
43
|
router,
|
|
41
44
|
getState,
|
|
42
45
|
setState,
|
|
@@ -45,18 +48,22 @@ export function useOnAction({
|
|
|
45
48
|
beforeRemoveListeners,
|
|
46
49
|
routerConfigOptions,
|
|
47
50
|
emitter,
|
|
48
|
-
}: Options) {
|
|
51
|
+
}: Options<State>) {
|
|
49
52
|
const {
|
|
50
53
|
onAction: onActionParent,
|
|
51
54
|
onRouteFocus: onRouteFocusParent,
|
|
52
55
|
addListener: addListenerParent,
|
|
53
56
|
onDispatchAction,
|
|
54
|
-
|
|
57
|
+
flushUpdates,
|
|
58
|
+
} = React.use(NavigationBuilderContext);
|
|
59
|
+
|
|
60
|
+
const tree = React.use(StaticTreeContext);
|
|
61
|
+
const consumedParams = React.use(ConsumedParamsContext);
|
|
55
62
|
|
|
56
63
|
const routerConfigOptionsRef =
|
|
57
64
|
React.useRef<RouterConfigOptions>(routerConfigOptions);
|
|
58
65
|
|
|
59
|
-
React.
|
|
66
|
+
React.useInsertionEffect(() => {
|
|
60
67
|
routerConfigOptionsRef.current = routerConfigOptions;
|
|
61
68
|
});
|
|
62
69
|
|
|
@@ -65,6 +72,11 @@ export function useOnAction({
|
|
|
65
72
|
action: NavigationAction,
|
|
66
73
|
visitedNavigators: Set<string> = new Set<string>()
|
|
67
74
|
) => {
|
|
75
|
+
// Apply any pending state updates scheduled during render before handling the action
|
|
76
|
+
// Otherwise the action will be handled with an outdated state,
|
|
77
|
+
// and the pending updates will overwrite the changes from the action
|
|
78
|
+
flushUpdates();
|
|
79
|
+
|
|
68
80
|
const state = getState();
|
|
69
81
|
|
|
70
82
|
// Since actions can bubble both up and down, they could come to the same navigator again
|
|
@@ -87,9 +99,18 @@ export function useOnAction({
|
|
|
87
99
|
result =
|
|
88
100
|
result === null && action.target === state.key ? state : result;
|
|
89
101
|
|
|
90
|
-
if (result !== null) {
|
|
91
|
-
|
|
102
|
+
if (result !== null && result.stale !== false) {
|
|
103
|
+
// Some actions (e.g. `RESET`) may return a stale state from the router
|
|
104
|
+
// We rehydrate it before storing so the stored state is always usable
|
|
105
|
+
// Otherwise anything reading the state before the next render
|
|
106
|
+
// (e.g. another dispatch immediately after) would get an outdated state
|
|
107
|
+
result = router.getRehydratedState(
|
|
108
|
+
result,
|
|
109
|
+
routerConfigOptionsRef.current
|
|
110
|
+
);
|
|
111
|
+
}
|
|
92
112
|
|
|
113
|
+
if (result !== null) {
|
|
93
114
|
if (state !== result) {
|
|
94
115
|
const isPrevented = shouldPreventRemove(
|
|
95
116
|
emitter,
|
|
@@ -100,10 +121,34 @@ export function useOnAction({
|
|
|
100
121
|
);
|
|
101
122
|
|
|
102
123
|
if (isPrevented) {
|
|
124
|
+
onDispatchAction(action, true);
|
|
125
|
+
|
|
103
126
|
return true;
|
|
104
127
|
}
|
|
105
128
|
|
|
129
|
+
if (getState() !== state) {
|
|
130
|
+
// Listeners for 'beforeRemove' may dispatch actions that change the state
|
|
131
|
+
// Then the result we have is outdated and would overwrite those changes
|
|
132
|
+
// So we handle the action again to calculate the result with the latest state
|
|
133
|
+
return onAction(action, new Set<string>());
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
onDispatchAction(action, false);
|
|
137
|
+
|
|
138
|
+
if (tree) {
|
|
139
|
+
const loader = getLoaderForStateChange(
|
|
140
|
+
tree,
|
|
141
|
+
result,
|
|
142
|
+
state,
|
|
143
|
+
consumedParams
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
loader?.();
|
|
147
|
+
}
|
|
148
|
+
|
|
106
149
|
setState(result);
|
|
150
|
+
} else {
|
|
151
|
+
onDispatchAction(action, true);
|
|
107
152
|
}
|
|
108
153
|
|
|
109
154
|
if (onRouteFocusParent !== undefined) {
|
|
@@ -132,7 +177,7 @@ export function useOnAction({
|
|
|
132
177
|
for (let i = actionListeners.length - 1; i >= 0; i--) {
|
|
133
178
|
const listener = actionListeners[i];
|
|
134
179
|
|
|
135
|
-
if (listener(action, visitedNavigators)) {
|
|
180
|
+
if (listener?.(action, visitedNavigators)) {
|
|
136
181
|
return true;
|
|
137
182
|
}
|
|
138
183
|
}
|
|
@@ -143,7 +188,9 @@ export function useOnAction({
|
|
|
143
188
|
[
|
|
144
189
|
actionListeners,
|
|
145
190
|
beforeRemoveListeners,
|
|
191
|
+
consumedParams,
|
|
146
192
|
emitter,
|
|
193
|
+
flushUpdates,
|
|
147
194
|
getState,
|
|
148
195
|
key,
|
|
149
196
|
onActionParent,
|
|
@@ -151,6 +198,7 @@ export function useOnAction({
|
|
|
151
198
|
onRouteFocusParent,
|
|
152
199
|
router,
|
|
153
200
|
setState,
|
|
201
|
+
tree,
|
|
154
202
|
]
|
|
155
203
|
);
|
|
156
204
|
|
|
@@ -160,7 +208,7 @@ export function useOnAction({
|
|
|
160
208
|
beforeRemoveListeners,
|
|
161
209
|
});
|
|
162
210
|
|
|
163
|
-
React.
|
|
211
|
+
React.useInsertionEffect(
|
|
164
212
|
() => addListenerParent?.('action', onAction),
|
|
165
213
|
[addListenerParent, onAction]
|
|
166
214
|
);
|
package/src/useOnGetState.tsx
CHANGED
|
@@ -14,8 +14,8 @@ type Options = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
17
|
-
const { addKeyedListener } = React.
|
|
18
|
-
const route = React.
|
|
17
|
+
const { addKeyedListener } = React.use(NavigationBuilderContext);
|
|
18
|
+
const route = React.use(NavigationRouteContext);
|
|
19
19
|
const key = route ? route.key : 'root';
|
|
20
20
|
|
|
21
21
|
const getRehydratedState = React.useCallback(() => {
|
|
@@ -39,7 +39,9 @@ export function useOnGetState({ getState, getStateListeners }: Options) {
|
|
|
39
39
|
return { ...state, routes };
|
|
40
40
|
}, [getState, getStateListeners]);
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
// Use insertion effect to preserve the listener under `<Activity mode="hidden">`
|
|
43
|
+
// So `getRootState` will still return state of nested navigators
|
|
44
|
+
React.useInsertionEffect(() => {
|
|
43
45
|
return addKeyedListener?.('getState', key, getRehydratedState);
|
|
44
46
|
}, [addKeyedListener, getRehydratedState, key]);
|
|
45
47
|
}
|