-
-
Notifications
You must be signed in to change notification settings - Fork 514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: provide a way to prevent native navigation #801
Conversation
It seems not working now. (I rebased it with latest version) |
Yeah, I changed the implementation and added a prop |
Then, does this PR compatible with |
I haven't yet rebased the PR to the newest master, but it should be compatible with both versions. |
It works well on both versions. (It was my problem) react-native-screens+2.18.0.patch
|
iOS seems not supporting this feature officially. |
Yeah, maybe it is a way to go, but I think it will be left for the users to decide about the custom back button. We expose prop |
@WoLewicki wanted to follow up from my comments on the RN discord about this. Do you think this PR will get merged soon? This feature will really improve the UX of forms by asking users if they want to discard unsaved changes. I think it’s totally fair to require a custom back button to implement this behavior. I’m happy to add this to the docs if it would help move the PR along :) If I want to test it, should I just generate a patch from this PR, and then use the thanks! |
I added another implementation on |
createNativeStackNavigator/README.md
Outdated
@@ -85,6 +85,15 @@ String that applies `rtl` or `ltr` form to the stack. On Android, you have to ad | |||
|
|||
Boolean indicating whether to show the menu on longPress of iOS >= 14 back button. Only supported on iOS. | |||
|
|||
#### `enableNativeBackButtonDismissal` (Android only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd name it nativeBackButtonDismissalEnabled
to match the naming patterns of other APIs in React Navigation
src/native-stack/index.tsx
Outdated
@@ -11,6 +11,7 @@ export { default as NativeStackView } from './views/NativeStackView'; | |||
/** | |||
* Utilities | |||
*/ | |||
export { default as usePreventDismiss } from './utils/usePreventDismiss'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make this part of the screens package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m currently using v5. On web, I use stack navigation, and on ios/android I use native-stack.
Should I use this hook only on native, and then use the typical beforeRemove
event listener in an effect on web?
(Once I upgrade to v6 I assume this won’t matter, but it’s going to take me a little bit.)
Can this be merged in assuming it works? |
createNativeStackNavigator/README.md
Outdated
#### `nativeBackButtonDismissalEnabled` (Android only) | ||
|
||
Boolean indicating whether, when the Android default back button is clicked, the `pop` action should be performed on the native side or on the JS side to be able to prevent it. | ||
Unfortunately the same behavior is not available on iOS since the behavior of native back button cannot be changed there. In order to prevent the dismiss there, you should provide your own back button using `headerLeft`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a Component that we can use to provide the back button with the same stylings as the native one including the chevron and the localized Back
text?
native-stack/README.md
Outdated
@@ -297,6 +304,58 @@ function Home() { | |||
} | |||
``` | |||
|
|||
#### `usePreventDismiss` (iOS only) | |||
|
|||
A hook to be used in order to prevent the native dismissal options (swipe and default header back button) on iOS. It should be used along with `react-navigation` `beforeRemove` listener to provide the behavior similar to the one in `stack` navigator. Example of usage: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add a note (assuming it is implemented as follows)
Using this on platforms other than iOS will be a noop.
native-stack/README.md
Outdated
@@ -297,6 +304,58 @@ function Home() { | |||
} | |||
``` | |||
|
|||
#### `usePreventDismiss` (iOS only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be better to use usePreventNativeDismiss
since this is specifically to disable native behaviour.
A few questions:
What does the behavior look like for gestures here? Does it fully block the ability to swipe? Or does it let you swipe, and then snap the screen back into place if there are unsaved changes? I think the second approach would be ideal, similar to the Native modal.
The docs recommend using What if this PR implemented the
I’m slightly confused by what the option is on the screen. Is that just an added way to prevent Native dismissal? Or do you need to both use the hook and pass the option to each screen? Thanks @WoLewicki @kacperkapusciak! |
After consultation with @satya164, we decided to merge only the native part of code for now in order for it to be available in next Expo SDK. The JS part is yet to be decided, probably some generic way to apply navigation preventing via a hook will be exposed. Only part left is the change of default Android back button behavior being now sending an event with dismiss to JS instead of popping the screen natively. |
@WoLewicki sounds good, thanks for the update. Let me know if I can help in any way. Will these Native changes also apply to React Navigation v6's Native stack? |
After these changes are released, you can use the newest |
Link to @react-navigation issue? |
Description
Updated the behavior of native Android back button to fire an event to JS with
goBack()
action instead of triggering navigation on the native side by default. It allows the user to discard the navigation action. Requested in #742.Keep in mind that this can be considered BREAKING CHANGE if you relied on default header back button native dismissal. It can be switched by setting
nativeBackButtonDismissalEnabled: true
on the screen.Unfortunately, there seems to be no way to prevent navigation on iOS default back button clicked.
reverted on the JS side
Instead, the navigation state can be restored after the end of the transition.
Also added the similar abstraction to swipe dismiss and modal dismiss on iOS.
Changes
Added new event
HeaderBackButtonClickedEvent
which is fired when the native Android header back button is clicked andnativeBackButtonDismissalEnabled: false
(which is default) is applied (before, clicking this button fired dismiss action on the native side without taking JS navigation into consideration). This event then triggers the same action asdismiss
event and can be prevented by user. It makes all the options of navigating back on Android (hw back button, callingnavigation.goBack()
and header back button) to behave the same.reverted on the JS side
Added similar abstraction for default native header back button, swipe dismiss and modal dismiss on iOS. It can be cancelled by setting
preventNativeDismiss: true
which triggersonNativeDismissCancelled
callback. It callsnavigation.pop
by default and can be overridden by the user.Checklist