@react-navigation/core 6.2.2 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -11
- package/lib/commonjs/PreventRemoveContext.js +17 -0
- package/lib/commonjs/PreventRemoveContext.js.map +1 -0
- package/lib/commonjs/PreventRemoveProvider.js +114 -0
- package/lib/commonjs/PreventRemoveProvider.js.map +1 -0
- package/lib/commonjs/getStateFromPath.js +1 -1
- package/lib/commonjs/getStateFromPath.js.map +1 -1
- package/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/useComponent.js +22 -12
- package/lib/commonjs/useComponent.js.map +1 -1
- package/lib/commonjs/useEventEmitter.js +1 -1
- package/lib/commonjs/useEventEmitter.js.map +1 -1
- package/lib/commonjs/useFocusEffect.js +1 -1
- package/lib/commonjs/useFocusEffect.js.map +1 -1
- package/lib/commonjs/useKeyedChildListeners.js +2 -2
- package/lib/commonjs/useKeyedChildListeners.js.map +1 -1
- package/lib/commonjs/useNavigationBuilder.js +4 -2
- package/lib/commonjs/useNavigationBuilder.js.map +1 -1
- package/lib/commonjs/usePreventRemove.js +59 -0
- package/lib/commonjs/usePreventRemove.js.map +1 -0
- package/lib/commonjs/usePreventRemoveContext.js +27 -0
- package/lib/commonjs/usePreventRemoveContext.js.map +1 -0
- package/lib/module/PreventRemoveContext.js +9 -0
- package/lib/module/PreventRemoveContext.js.map +1 -0
- package/lib/module/PreventRemoveProvider.js +96 -0
- package/lib/module/PreventRemoveProvider.js.map +1 -0
- package/lib/module/getStateFromPath.js +1 -1
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useComponent.js +23 -12
- package/lib/module/useComponent.js.map +1 -1
- package/lib/module/useEventEmitter.js +1 -1
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useFocusEffect.js +1 -1
- package/lib/module/useFocusEffect.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +2 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +3 -2
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/usePreventRemove.js +41 -0
- package/lib/module/usePreventRemove.js.map +1 -0
- package/lib/module/usePreventRemoveContext.js +12 -0
- package/lib/module/usePreventRemoveContext.js.map +1 -0
- package/lib/typescript/src/PreventRemoveContext.d.ts +13 -0
- package/lib/typescript/src/PreventRemoveProvider.d.ts +9 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/types.d.ts +10 -6
- package/lib/typescript/src/useComponent.d.ts +5 -1
- package/lib/typescript/src/useDescriptors.d.ts +3 -3
- package/lib/typescript/src/useNavigationBuilder.d.ts +9 -7
- package/lib/typescript/src/useNavigationHelpers.d.ts +3 -3
- package/lib/typescript/src/usePreventRemove.d.ts +12 -0
- package/lib/typescript/src/usePreventRemoveContext.d.ts +4 -0
- package/package.json +7 -5
- package/src/PreventRemoveContext.tsx +21 -0
- package/src/PreventRemoveProvider.tsx +126 -0
- package/src/getStateFromPath.tsx +4 -1
- package/src/index.tsx +4 -0
- package/src/types.tsx +39 -14
- package/src/useComponent.tsx +19 -12
- package/src/useEventEmitter.tsx +3 -1
- package/src/useFocusEffect.tsx +1 -1
- package/src/useKeyedChildListeners.tsx +6 -4
- package/src/useNavigationBuilder.tsx +6 -3
- package/src/usePreventRemove.tsx +51 -0
- package/src/usePreventRemoveContext.tsx +15 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid/non-secure';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import useLatestCallback from 'use-latest-callback';
|
|
4
|
+
|
|
5
|
+
import NavigationHelpersContext from './NavigationHelpersContext';
|
|
6
|
+
import NavigationRouteContext from './NavigationRouteContext';
|
|
7
|
+
import PreventRemoveContext, { PreventedRoutes } from './PreventRemoveContext';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type PreventedRoutesMap = Map<
|
|
14
|
+
string,
|
|
15
|
+
{
|
|
16
|
+
routeKey: string;
|
|
17
|
+
preventRemove: boolean;
|
|
18
|
+
}
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Util function to transform map of prevented routes to a simpler object.
|
|
23
|
+
*/
|
|
24
|
+
const transformPreventedRoutes = (
|
|
25
|
+
preventedRoutesMap: PreventedRoutesMap
|
|
26
|
+
): PreventedRoutes => {
|
|
27
|
+
const preventedRoutesToTransform = [...preventedRoutesMap.values()];
|
|
28
|
+
|
|
29
|
+
const preventedRoutes = preventedRoutesToTransform.reduce<PreventedRoutes>(
|
|
30
|
+
(acc, { routeKey, preventRemove }) => {
|
|
31
|
+
acc[routeKey] = {
|
|
32
|
+
preventRemove: acc[routeKey]?.preventRemove || preventRemove,
|
|
33
|
+
};
|
|
34
|
+
return acc;
|
|
35
|
+
},
|
|
36
|
+
{}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return preventedRoutes;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Component used for managing which routes have to be prevented from removal in native-stack.
|
|
44
|
+
*/
|
|
45
|
+
export default function PreventRemoveProvider({ children }: Props) {
|
|
46
|
+
const [parentId] = React.useState(() => nanoid());
|
|
47
|
+
const [preventedRoutesMap, setPreventedRoutesMap] =
|
|
48
|
+
React.useState<PreventedRoutesMap>(new Map());
|
|
49
|
+
|
|
50
|
+
const navigation = React.useContext(NavigationHelpersContext);
|
|
51
|
+
const route = React.useContext(NavigationRouteContext);
|
|
52
|
+
|
|
53
|
+
const preventRemoveContextValue = React.useContext(PreventRemoveContext);
|
|
54
|
+
// take `setPreventRemove` from parent context - if exist it means we're in a nested context
|
|
55
|
+
const setParentPrevented = preventRemoveContextValue?.setPreventRemove;
|
|
56
|
+
|
|
57
|
+
const setPreventRemove = useLatestCallback(
|
|
58
|
+
(id: string, routeKey: string, preventRemove: boolean): void => {
|
|
59
|
+
if (
|
|
60
|
+
preventRemove &&
|
|
61
|
+
(navigation == null ||
|
|
62
|
+
navigation
|
|
63
|
+
?.getState()
|
|
64
|
+
.routes.every((route) => route.key !== routeKey))
|
|
65
|
+
) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Couldn't find a route with the key ${routeKey}. Is your component inside NavigationContent?`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setPreventedRoutesMap((prevPrevented) => {
|
|
72
|
+
// values haven't changed - do nothing
|
|
73
|
+
if (
|
|
74
|
+
routeKey === prevPrevented.get(id)?.routeKey &&
|
|
75
|
+
preventRemove === prevPrevented.get(id)?.preventRemove
|
|
76
|
+
) {
|
|
77
|
+
return prevPrevented;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const nextPrevented = new Map(prevPrevented);
|
|
81
|
+
|
|
82
|
+
if (preventRemove) {
|
|
83
|
+
nextPrevented.set(id, {
|
|
84
|
+
routeKey,
|
|
85
|
+
preventRemove,
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
nextPrevented.delete(id);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return nextPrevented;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const isPrevented = [...preventedRoutesMap.values()].some(
|
|
97
|
+
({ preventRemove }) => preventRemove
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
React.useEffect(() => {
|
|
101
|
+
if (route?.key !== undefined && setParentPrevented !== undefined) {
|
|
102
|
+
// when route is defined (and setParentPrevented) it means we're in a nested stack
|
|
103
|
+
// route.key then will be the route key of parent
|
|
104
|
+
setParentPrevented(parentId, route.key, isPrevented);
|
|
105
|
+
return () => {
|
|
106
|
+
setParentPrevented(parentId, route.key, false);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return;
|
|
111
|
+
}, [parentId, isPrevented, route?.key, setParentPrevented]);
|
|
112
|
+
|
|
113
|
+
const value = React.useMemo(
|
|
114
|
+
() => ({
|
|
115
|
+
setPreventRemove,
|
|
116
|
+
preventedRoutes: transformPreventedRoutes(preventedRoutesMap),
|
|
117
|
+
}),
|
|
118
|
+
[setPreventRemove, preventedRoutesMap]
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<PreventRemoveContext.Provider value={value}>
|
|
123
|
+
{children}
|
|
124
|
+
</PreventRemoveContext.Provider>
|
|
125
|
+
);
|
|
126
|
+
}
|
package/src/getStateFromPath.tsx
CHANGED
|
@@ -565,7 +565,10 @@ const parseQueryParams = (
|
|
|
565
565
|
|
|
566
566
|
if (parseConfig) {
|
|
567
567
|
Object.keys(params).forEach((name) => {
|
|
568
|
-
if (
|
|
568
|
+
if (
|
|
569
|
+
Object.hasOwnProperty.call(parseConfig, name) &&
|
|
570
|
+
typeof params[name] === 'string'
|
|
571
|
+
) {
|
|
569
572
|
params[name] = parseConfig[name](params[name] as string);
|
|
570
573
|
}
|
|
571
574
|
});
|
package/src/index.tsx
CHANGED
|
@@ -11,6 +11,8 @@ export { default as NavigationContainerRefContext } from './NavigationContainerR
|
|
|
11
11
|
export { default as NavigationContext } from './NavigationContext';
|
|
12
12
|
export { default as NavigationHelpersContext } from './NavigationHelpersContext';
|
|
13
13
|
export { default as NavigationRouteContext } from './NavigationRouteContext';
|
|
14
|
+
export { default as PreventRemoveContext } from './PreventRemoveContext';
|
|
15
|
+
export { default as PreventRemoveProvider } from './PreventRemoveProvider';
|
|
14
16
|
export * from './types';
|
|
15
17
|
export { default as useFocusEffect } from './useFocusEffect';
|
|
16
18
|
export { default as useIsFocused } from './useIsFocused';
|
|
@@ -18,6 +20,8 @@ export { default as useNavigation } from './useNavigation';
|
|
|
18
20
|
export { default as useNavigationBuilder } from './useNavigationBuilder';
|
|
19
21
|
export { default as useNavigationContainerRef } from './useNavigationContainerRef';
|
|
20
22
|
export { default as useNavigationState } from './useNavigationState';
|
|
23
|
+
export { default as UNSTABLE_usePreventRemove } from './usePreventRemove';
|
|
24
|
+
export { default as usePreventRemoveContext } from './usePreventRemoveContext';
|
|
21
25
|
export { default as useRoute } from './useRoute';
|
|
22
26
|
export { default as validatePathConfig } from './validatePathConfig';
|
|
23
27
|
export * from '@react-navigation/routers';
|
package/src/types.tsx
CHANGED
|
@@ -192,9 +192,18 @@ type NavigationHelpersCommon<
|
|
|
192
192
|
* @param [params] Params object for the route.
|
|
193
193
|
*/
|
|
194
194
|
navigate<RouteName extends keyof ParamList>(
|
|
195
|
-
...args:
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
...args: // this first condition allows us to iterate over a union type
|
|
196
|
+
// This is to avoid getting a union of all the params from `ParamList[RouteName]`,
|
|
197
|
+
// which will get our types all mixed up if a union RouteName is passed in.
|
|
198
|
+
RouteName extends unknown
|
|
199
|
+
? // This condition checks if the params are optional,
|
|
200
|
+
// which means it's either undefined or a union with undefined
|
|
201
|
+
undefined extends ParamList[RouteName]
|
|
202
|
+
?
|
|
203
|
+
| [screen: RouteName] // if the params are optional, we don't have to provide it
|
|
204
|
+
| [screen: RouteName, params: ParamList[RouteName]]
|
|
205
|
+
: [screen: RouteName, params: ParamList[RouteName]]
|
|
206
|
+
: never
|
|
198
207
|
): void;
|
|
199
208
|
|
|
200
209
|
/**
|
|
@@ -203,14 +212,16 @@ type NavigationHelpersCommon<
|
|
|
203
212
|
* @param route Object with `key` or `name` for the route to navigate to, and a `params` object.
|
|
204
213
|
*/
|
|
205
214
|
navigate<RouteName extends keyof ParamList>(
|
|
206
|
-
options:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
215
|
+
options: RouteName extends unknown
|
|
216
|
+
?
|
|
217
|
+
| { key: string; params?: ParamList[RouteName]; merge?: boolean }
|
|
218
|
+
| {
|
|
219
|
+
name: RouteName;
|
|
220
|
+
key?: string;
|
|
221
|
+
params: ParamList[RouteName];
|
|
222
|
+
merge?: boolean;
|
|
223
|
+
}
|
|
224
|
+
: never
|
|
214
225
|
): void;
|
|
215
226
|
|
|
216
227
|
/**
|
|
@@ -325,7 +336,11 @@ export type NavigationProp<
|
|
|
325
336
|
*
|
|
326
337
|
* @param params Params object for the current route.
|
|
327
338
|
*/
|
|
328
|
-
setParams(
|
|
339
|
+
setParams(
|
|
340
|
+
params: ParamList[RouteName] extends undefined
|
|
341
|
+
? undefined
|
|
342
|
+
: Partial<ParamList[RouteName]>
|
|
343
|
+
): void;
|
|
329
344
|
|
|
330
345
|
/**
|
|
331
346
|
* Update the options for the route.
|
|
@@ -436,6 +451,16 @@ export type ScreenListeners<
|
|
|
436
451
|
>;
|
|
437
452
|
}>;
|
|
438
453
|
|
|
454
|
+
type ScreenComponentType<
|
|
455
|
+
ParamList extends ParamListBase,
|
|
456
|
+
RouteName extends keyof ParamList
|
|
457
|
+
> =
|
|
458
|
+
| React.ComponentType<{
|
|
459
|
+
route: RouteProp<ParamList, RouteName>;
|
|
460
|
+
navigation: any;
|
|
461
|
+
}>
|
|
462
|
+
| React.ComponentType<{}>;
|
|
463
|
+
|
|
439
464
|
export type RouteConfigComponent<
|
|
440
465
|
ParamList extends ParamListBase,
|
|
441
466
|
RouteName extends keyof ParamList
|
|
@@ -444,7 +469,7 @@ export type RouteConfigComponent<
|
|
|
444
469
|
/**
|
|
445
470
|
* React component to render for this screen.
|
|
446
471
|
*/
|
|
447
|
-
component:
|
|
472
|
+
component: ScreenComponentType<ParamList, RouteName>;
|
|
448
473
|
getComponent?: never;
|
|
449
474
|
children?: never;
|
|
450
475
|
}
|
|
@@ -452,7 +477,7 @@ export type RouteConfigComponent<
|
|
|
452
477
|
/**
|
|
453
478
|
* Lazily get a React component to render for this screen.
|
|
454
479
|
*/
|
|
455
|
-
getComponent: () =>
|
|
480
|
+
getComponent: () => ScreenComponentType<ParamList, RouteName>;
|
|
456
481
|
component?: never;
|
|
457
482
|
children?: never;
|
|
458
483
|
}
|
package/src/useComponent.tsx
CHANGED
|
@@ -1,30 +1,37 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
type Render = (children: React.ReactNode) => JSX.Element;
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
render: Render;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const NavigationContent = ({ render, children }: Props) => {
|
|
11
|
+
return render(children);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function useComponent(render: Render) {
|
|
15
|
+
const renderRef = React.useRef<Render | null>(render);
|
|
8
16
|
|
|
9
17
|
// Normally refs shouldn't be mutated in render
|
|
10
18
|
// But we return a component which will be rendered
|
|
11
19
|
// So it's just for immediate consumption
|
|
12
|
-
|
|
20
|
+
renderRef.current = render;
|
|
13
21
|
|
|
14
22
|
React.useEffect(() => {
|
|
15
|
-
|
|
23
|
+
renderRef.current = null;
|
|
16
24
|
});
|
|
17
25
|
|
|
18
|
-
return React.useRef((
|
|
19
|
-
const
|
|
26
|
+
return React.useRef(({ children }: { children: React.ReactNode }) => {
|
|
27
|
+
const render = renderRef.current;
|
|
20
28
|
|
|
21
|
-
if (
|
|
29
|
+
if (render === null) {
|
|
22
30
|
throw new Error(
|
|
23
31
|
'The returned component must be rendered in the same render phase as the hook.'
|
|
24
32
|
);
|
|
25
33
|
}
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
return <Component {...props} {...rest} />;
|
|
35
|
+
return <NavigationContent render={render}>{children}</NavigationContent>;
|
|
29
36
|
}).current;
|
|
30
37
|
}
|
package/src/useEventEmitter.tsx
CHANGED
|
@@ -21,7 +21,9 @@ export default function useEventEmitter<T extends Record<string, any>>(
|
|
|
21
21
|
listenRef.current = listen;
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
const listeners = React.useRef<Record<string, Record<string, Listeners>>>(
|
|
24
|
+
const listeners = React.useRef<Record<string, Record<string, Listeners>>>(
|
|
25
|
+
Object.create(null)
|
|
26
|
+
);
|
|
25
27
|
|
|
26
28
|
const create = React.useCallback((target: string) => {
|
|
27
29
|
const removeListener = (type: string, callback: (data: any) => void) => {
|
package/src/useFocusEffect.tsx
CHANGED
|
@@ -52,7 +52,7 @@ export default function useFocusEffect(effect: EffectCallback) {
|
|
|
52
52
|
'Instead, write the async function inside your effect ' +
|
|
53
53
|
'and call it immediately:\n\n' +
|
|
54
54
|
'useFocusEffect(\n' +
|
|
55
|
-
' React.useCallback() => {\n' +
|
|
55
|
+
' React.useCallback(() => {\n' +
|
|
56
56
|
' async function fetchData() {\n' +
|
|
57
57
|
' // You can await here\n' +
|
|
58
58
|
' const response = await MyAPI.getData(someId);\n' +
|
|
@@ -11,10 +11,12 @@ export default function useKeyedChildListeners() {
|
|
|
11
11
|
string,
|
|
12
12
|
KeyedListenerMap[K] | undefined
|
|
13
13
|
>;
|
|
14
|
-
}>(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
}>(
|
|
15
|
+
Object.assign(Object.create(null), {
|
|
16
|
+
getState: {},
|
|
17
|
+
beforeRemove: {},
|
|
18
|
+
})
|
|
19
|
+
);
|
|
18
20
|
|
|
19
21
|
const addKeyedListener = React.useCallback(
|
|
20
22
|
<T extends keyof KeyedListenerMap>(
|
|
@@ -19,6 +19,7 @@ import isRecordEqual from './isRecordEqual';
|
|
|
19
19
|
import NavigationHelpersContext from './NavigationHelpersContext';
|
|
20
20
|
import NavigationRouteContext from './NavigationRouteContext';
|
|
21
21
|
import NavigationStateContext from './NavigationStateContext';
|
|
22
|
+
import PreventRemoveProvider from './PreventRemoveProvider';
|
|
22
23
|
import Screen from './Screen';
|
|
23
24
|
import {
|
|
24
25
|
DefaultNavigatorOptions,
|
|
@@ -690,9 +691,11 @@ export default function useNavigationBuilder<
|
|
|
690
691
|
descriptors,
|
|
691
692
|
});
|
|
692
693
|
|
|
693
|
-
const NavigationContent = useComponent(
|
|
694
|
-
value
|
|
695
|
-
|
|
694
|
+
const NavigationContent = useComponent((children: React.ReactNode) => (
|
|
695
|
+
<NavigationHelpersContext.Provider value={navigation}>
|
|
696
|
+
<PreventRemoveProvider>{children}</PreventRemoveProvider>
|
|
697
|
+
</NavigationHelpersContext.Provider>
|
|
698
|
+
));
|
|
696
699
|
|
|
697
700
|
return {
|
|
698
701
|
state,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { NavigationAction } from '@react-navigation/routers';
|
|
2
|
+
import { nanoid } from 'nanoid/non-secure';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import useLatestCallback from 'use-latest-callback';
|
|
5
|
+
|
|
6
|
+
import type { EventListenerCallback, EventMapCore } from './types';
|
|
7
|
+
import useNavigation from './useNavigation';
|
|
8
|
+
import usePreventRemoveContext from './usePreventRemoveContext';
|
|
9
|
+
import useRoute from './useRoute';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook to prevent screen from being removed. Can be used to prevent users from leaving the screen.
|
|
13
|
+
*
|
|
14
|
+
* @param preventRemove Boolean indicating whether to prevent screen from being removed.
|
|
15
|
+
* @param callback Function which is executed when screen was prevented from being removed.
|
|
16
|
+
*/
|
|
17
|
+
export default function usePreventRemove(
|
|
18
|
+
preventRemove: boolean,
|
|
19
|
+
callback: (options: { data: { action: NavigationAction } }) => void
|
|
20
|
+
) {
|
|
21
|
+
const [id] = React.useState(() => nanoid());
|
|
22
|
+
|
|
23
|
+
const navigation = useNavigation();
|
|
24
|
+
const { key: routeKey } = useRoute();
|
|
25
|
+
|
|
26
|
+
const { setPreventRemove } = usePreventRemoveContext();
|
|
27
|
+
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
setPreventRemove(id, routeKey, preventRemove);
|
|
30
|
+
return () => {
|
|
31
|
+
setPreventRemove(id, routeKey, false);
|
|
32
|
+
};
|
|
33
|
+
}, [setPreventRemove, id, routeKey, preventRemove]);
|
|
34
|
+
|
|
35
|
+
const beforeRemoveListener = useLatestCallback<
|
|
36
|
+
EventListenerCallback<EventMapCore<any>, 'beforeRemove'>
|
|
37
|
+
>((e) => {
|
|
38
|
+
if (!preventRemove) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
|
|
44
|
+
callback({ data: e.data });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
React.useEffect(
|
|
48
|
+
() => navigation?.addListener('beforeRemove', beforeRemoveListener),
|
|
49
|
+
[navigation, beforeRemoveListener]
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import PreventRemoveContext from './PreventRemoveContext';
|
|
4
|
+
|
|
5
|
+
export default function usePreventRemoveContext() {
|
|
6
|
+
const value = React.useContext(PreventRemoveContext);
|
|
7
|
+
|
|
8
|
+
if (value == null) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
"Couldn't find the prevent remove context. Is your component inside NavigationContent?"
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return value;
|
|
15
|
+
}
|