A lot of times, we want to prompt before leaving a screen if we have unsaved changes. Currently, we need to handle multiple cases to prevent this:
- Disable swipe gestures
- Override the back button in header
- Override the hardware back button on Android
This PR adds a new event which is emitted before a screen gets removed, and the developer has a chance to ask the user before closing the screen.
Example:
```js
React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
if (!hasUnsavedChanges) {
return;
}
e.preventDefault();
Alert.alert(
'Discard changes?',
'You have unsaved changes. Are you sure to discard them and leave the screen?',
[
{ text: "Don't leave", style: 'cancel', onPress: () => {} },
{
text: 'Discard',
style: 'destructive',
onPress: () => navigation.dispatch(e.data.action),
},
]
);
}),
[navigation, hasUnsavedChanges]
);
```
The PR changes a few things about linking configuration:
- Moves the configuration for screens to a screens property so that it's possible to specify other options like `initialRouteName` for the navigator at root
- The nesting in the configuration needs to strictly match the shape of the navigation tree, it can't just rely on URL's shape anymore
- If a screen is not specified in the configuration, it won't be parsed to/from the URL (this is essential to handle unmatched screens)
- Treat `path: ''` and no specified path in the same way, unless `exact` is specified
- Disallow specifying unmatched screen with old format
- Add support for `initialRouteName` at top level
- Automatically adapt old configuration to new format
Added `collapsable={false}` to the View in order for the Android to render screens properly. This issue is most probably similar to 9c06a92d09 but fixes it on Android since the View seems to be removed from a native view hierarchy due to not drawing anything. To see the bug go to https://github.com/software-mansion/react-native-screens/issues/544.
The `devtools` package extracts the redux devtools extension integration to a separate package. In future we can add more tools such as flipper integration to this package.
Usage:
```js
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { useReduxDevToolsExtension } from '@react-navigation/devtools';
export default function App() {
const navigationRef = React.useRef();
useReduxDevToolsExtension(navigationRef);
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
```
Currently, to access the focused child screen, we need to do something like this:
```js
const routeName = route.state
? route.state.routes[route.state.index].name
: route.params?.screen || 'Feed';
```
However, it doesn't handle some cases, such as when `route.state` is partial. This helper will make it easier:
```js
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Feed';
```