This commit adds a new optional property on the `route` object called `path`.
This property will be added if the screen was opened from a deep link.
Having this property helps with few things:
- Preserve the URL when the path was unmatched, e.g. 404 routes
- Expose the path to the user so they could handle it manually if needed, e.g. open in a webview
- Avoid changing URL if state to path doesn't match current path, e.g. if orders of params change
Fixes#9102
BREAKING CHANGE: This commit moves options from `drawerContentOptions` to regular `options` in order to reduce confusion between the two, as well as to make it more flexible to configure the drawer on a per screen basis.
BREAKING CHANGE: Previously, the stack header accepted scene and previous scene which contained things such as descriptor, navigation prop, progress etc. The commit simplifies them to pass `route`, `navigation`, `options` and `progress` directly to the header. Similaryly, the `previous` argument now contains `options`, `route` and `progress`.
This commit adds new `header` and `headerShown` options in drawer navigator to be able to show a header, along with a bunch of header related options similar to stack navigator.
Historically, we have suggested to nest a stack navigator inside drawer navigator to render a header. While it works, it's not efficient to nest an entire navigator just for a header, considering it adds a lot of additional overhead from the code to handle animations, gestures etc. which won't ever be run in this case. It also increases the view hierarchy which has negative impacts on performance on Android, and could cause content not to render on older iOS devices.
Another issue with the approach is that since drawer navigator is at the root in this setup, it's possible to open drawer from every screen in the stack navigator, which usually isn't the expected behaviour. It's necessary to write additional code to disable the gesture to open drawer in all screens but first.
In addition, users also need to add a custom drawer icon to the header manually to be able to toggle the drawer
If drawer navigator could render its own header we'd avoid all these shortcomings as well as make the code simpler.
For now, I have implemented a new `Header` component in drawer since it's way simpler than stack navigator header. Though we may consider creating a shared UI package and add such components there which all our navigators could use.
The `Header` includes a button to toggle the drawer by default, and supports customization options such as showing custom left/right/title components. For this commit, I have kept `headerShown` to `false` by default coz I wasn't sure if it'd be a breaking change to start showing headers in drawers. Probably we can toggle it to `true` by default in next major.
Previously, 'resetRoot' directly performed a 'setState' on the container instead of dispatching an action. This meant that hooks such as listener for 'preventRemove' won't be notified by it. This commit changes it to dispatch a regular 'RESET' action which will behave the same as other actions.
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]
);
```