Closed Livijn closed 2 years ago
Hi Livijn,
we had the same bug with "createNativeStackNavigator".
Using "createStackNavigator" from "@react-navigation/stack" fixed it for us.
Hope that helps! Philipp
I don't want to drop the benefits of using the native stack for this purpose. Thanks though.
hi @Livijn, did you find a workaround for this one?
Nope, not yet. Still waiting for @gorhom to reply.
Nope, not yet. Still waiting for @gorhom to reply.
right, I ended up using
<FullWindowOverlay style={StyleSheet.absoluteFill}>
from react-native-screens to wrap the bottom sheet; that brings it above the navigators. I found out about it here https://github.com/gorhom/react-native-portal, in case you also need to use a portal
hope this helps a bit in the meantime
If I wrap it like this: <FullWindowOverlay><BottomSheetModal /></FullWindowOverlay>
nothing changes. However, if I wrap the content like: <BottomSheetModal><FullWindowOverlay /></BottomSheetModal>
the content is placed correctly above the navigators. However, it breaks the animation etc of the sheet.
What way did you do it?
FullWindowOverlay
If I wrap it like this:
<FullWindowOverlay><BottomSheetModal /></FullWindowOverlay>
nothing changes. However, if I wrap the content like:<BottomSheetModal><FullWindowOverlay /></BottomSheetModal>
the content is placed correctly above the navigators. However, it breaks the animation etc of the sheet.What way did you do it?
`
I did add the correct styling. For now, I guess I'll go with the non-native stack navigator.
Guys, it worked for me <FullWindowOverlay style={StyleSheet.absoluteFill}><Portal><BottomSheet> {...}
Portal
usage didn't help me, I preferred to switch to the non-modal component (BottomSheet
) waiting for a better solution with BottomSheetModal
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
This issue was closed because it has been stalled for 5 days with no activity.
Hello! I figured a workaround which allow the use of any BottomSheetModal inside react-navigation's native modal screen:
For it to work, you must place a PortalProvider inside your base BottomSheetModalProvider (the one which is usually located inside you App.tsx file), this will be useful for later. Then, for each modal Screen in which you want to use your BottomSheetModal, you have to place yet another BottomSheetModalProvider and place another PortalProvider inside it. You may also create a generic component which will have the same purpose but cleaner.
Example:
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { PortalProvider } from '@gorhom/portal';
import { useMemo } from 'react';
import { NavigationModalScreenContainerContext } from './NavigationModalScreenContainer.context';
import {
NavigationModalScreenContainerContextProps,
NavigationModalScreenContainerProps
} from './NavigationModalScreenContainer.types';
export const NavigationModalScreenContainer = ({ children }: NavigationModalScreenContainerProps) => {
const contextValue = useMemo<NavigationModalScreenContainerContextProps>(
() => ({
isNavigationModal: true
}),
[]
);
return (
<BottomSheetModalProvider>
<PortalProvider>
<NavigationModalScreenContainerContext.Provider value={contextValue}>
{children}
</NavigationModalScreenContainerContext.Provider>
</PortalProvider>
</BottomSheetModalProvider>
);
};
Then, wrap every one of your BottomSheetModal inside a Portal component. This will force the sheet to render inside the react-navigation's native modal and not higher in the tree. From then, your sheets should work as expected with the only downside being that the backdrop won't be able to fill the entire screen (as it is only rendered inside your native modal screen).
See:
My solution was to use a Context.Provider inside NavigationModalScreenContainer
with a variable like isNavigationModal
, you can use this value to edit your backdrop opacity and / or add shadow if this value is true.
Once again, I advise you to create a generic component for all your BottomSheetModal which contains all the previous components and logic.
Hope this will help, have a nice day ☀️
Adding a <PortalProvider>
to the root of my app seemed to interfere with the <BottomSheetModalProvider>
that was already there (which already uses PortalProvider under the hood). Only every other bottom sheet I opened would become visible.
I got mine working simply by wrapping my react-navigation modal screen's contents in a <BottomSheetModalProvider>
:
function AppStack() {
return (
<NativeStack.Navigator>
{/* ... */}
<NativeStack.Group screenOptions={{ presentation: 'modal' }}>
<NativeStack.Screen
name="MyScreenThatNeedsToBeAbleToOpenABottomSheetModal"
component={MyScreenThatNeedsToBeAbleToOpenABottomSheetModal}
/>
</NativeStack.Group>
</NativeStack.Navigator>
)
}
function MyScreenThatNeedsToBeAbleToOpenABottomSheetModal() {
return (
<BottomSheetModalProvider>
{/* Screen content here, and one of these children can now open a BottomSheetModal */}
</BottomSheetModalProvider>
)
}
I made a PR #1086 to fix this issue, hope it will be merged soon :)
Adding a
<PortalProvider>
to the root of my app seemed to interfere with the<BottomSheetModalProvider>
that was already there (which already uses PortalProvider under the hood). Only every other bottom sheet I opened would become visible.I got mine working simply by wrapping my react-navigation modal screen's contents in a
<BottomSheetModalProvider>
:function AppStack() { return ( <NativeStack.Navigator> {/* ... */} <NativeStack.Group screenOptions={{ presentation: 'modal' }}> <NativeStack.Screen name="MyScreenThatNeedsToBeAbleToOpenABottomSheetModal" component={MyScreenThatNeedsToBeAbleToOpenABottomSheetModal} /> </NativeStack.Group> </NativeStack.Navigator> ) } function MyScreenThatNeedsToBeAbleToOpenABottomSheetModal() { return ( <BottomSheetModalProvider> {/* Screen content here, and one of these children can now open a BottomSheetModal */} </BottomSheetModalProvider> ) }
Not sure why this works but it does, thank you so much!
In my case, instead of using a react native navigation modal screen, I instead used a normal screen, but modified the animation to look like that of a modal. I know this might be the case for some of us.
In other words, instead of
<Stack.Screen
name="ModalScreen"
component={ModalScreen}
options={{presentation: 'fullScreenModal', headerShown: false}}
/>
I changed the configuration to this:
<Stack.Screen
name={ModalScreen}
component={ModalScreen}
options={{
headerShown: false,
animationTypeForReplace: 'push',
animation: 'slide_from_bottom',
}}
/>
Again, this doesn't directly solve the issue, but it is a work around I am very comfortable with, as it doesn't break any existing structure I have in place. Hope it helps ❤️
Adding a
<PortalProvider>
to the root of my app seemed to interfere with the<BottomSheetModalProvider>
that was already there (which already uses PortalProvider under the hood). Only every other bottom sheet I opened would become visible.I got mine working simply by wrapping my react-navigation modal screen's contents in a
<BottomSheetModalProvider>
:function AppStack() { return ( <NativeStack.Navigator> {/* ... */} <NativeStack.Group screenOptions={{ presentation: 'modal' }}> <NativeStack.Screen name="MyScreenThatNeedsToBeAbleToOpenABottomSheetModal" component={MyScreenThatNeedsToBeAbleToOpenABottomSheetModal} /> </NativeStack.Group> </NativeStack.Navigator> ) } function MyScreenThatNeedsToBeAbleToOpenABottomSheetModal() { return ( <BottomSheetModalProvider> {/* Screen content here, and one of these children can now open a BottomSheetModal */} </BottomSheetModalProvider> ) }
Using this approach in the context of a presentation: 'modal'
for me resulted in the backdrop being contained within the screen of that modal (as you might expect). Not a reliable solution if you expect the backdrop to cover the entire screen.
Ultimately I did something like:
import { FullWindowOverlay } from 'react-native-screens'
...
const renderContainerComponent = useCallback(
({ children }) => <FullWindowOverlay>{children}</FullWindowOverlay>,
[],
)
...
<BottomSheetModal containerComponent={renderContainerComponent}>
...
Adding containerComponent={({ children }) => <FullWindowOverlay>{children}</FullWindowOverlay>}
to my BottomSheetModal
weirdly causes the modal to flicker on open
Fixed by wrapping it in useCallback and only setting it on iOS
const containerComponent = useCallback((props: any) => <FullWindowOverlay>{props.children}</FullWindowOverlay>, []);
return <BottomSheetModal containerComponent={IS_IOS ? containerComponent : undefined}>...</BottomSheetModal>
Ultimately I did something like:
import { FullWindowOverlay } from 'react-native-screens' ... const renderContainerComponent = useCallback( ({ children }) => <FullWindowOverlay>{children}</FullWindowOverlay>, [], ) ... <BottomSheetModal containerComponent={renderContainerComponent}> ...
It works for me Why it works with FullWindowOverlay?
Why it works with FullWindowOverlay?
Because React Navigation's native stack renders modals in a new native view above the existing app, so anything rendered in the original root view will appear behind the modal.
Wrapping with a FullWindowOverlay
will add another native overlay above the modal, so now there's 3 native root views:
1) Your primary app
2) React navigation's modal overlay
3) BottomSheetModal
, wrapped wrapped in a FullWindowOverlay
Why it works with FullWindowOverlay?
Because React Navigation's native stack renders modals in a new native view above the existing app, so anything rendered in the original root view will appear behind the modal.
Wrapping with a
FullWindowOverlay
will add another native overlay above the modal, so now there's 3 native root views:
- Your primary app
- React navigation's modal overlay
BottomSheetModal
, wrapped wrapped in aFullWindowOverlay
It dose make sense Thank for your reply
Bug
The sheet is placed behind the @react-navigation/native modal.
Environment info
Steps To Reproduce
<BottomSheetModal>
in a screen withpresentation: "modal"
.Describe what you expected to happen:
The sheet is placed behind the modal. I expect the sheet to be in front of the modal that hosts the sheet. I've also tried wrapping the modal-component with the provider, but then I get
'BottomSheetModalInternalContext' cannot be null!
.Reproducible sample code
The snack template throws an error:
Cannot convert undefined or null to object