software-mansion / react-native-screens

Native navigation primitives for your React Native app.
https://docs.swmansion.com/react-native-screens/
MIT License
3.02k stars 512 forks source link

ScreenContainer crashes when rendered inside a React Native Modal #1769

Open aweary opened 1 year ago

aweary commented 1 year ago

Description

ScreenContainer tries to read a FragmentManager from the ReactRootView but if this is being rendered within a Modal component the native view will be attached to a DialogRootViewGroup which is attached to the native android.app.Dialog, so its not a child of a ReactRootView. A Dialog is the only way to trap screen reader focus on Android, so we have some use cases where we have to structure it this way.

As far as I can tell, it's just trying to read a FragmentManager from ReactRootView but it should be able to find a FragmentManager when nested inside DialogRootViewGroup as well

Steps to reproduce

  1. Create a native stack navigator with createNativeStackNavigator
  2. Render it inside Modal
  3. Run on an Android device

Snack or a link to a repository

https://gist.github.com/aweary/1f031cedb1cf0998597119acfa2373b7

Screens version

3.18.2

React Native version

0.70

Platforms

Android

JavaScript runtime

None

Workflow

None

Architecture

None

Build type

None

Device

None

Device model

No response

Acknowledgements

Yes

github-actions[bot] commented 1 year ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

pzatorski commented 11 months ago

Same issue here 🤕

eric-everbright commented 9 months ago

@aweary did you ever find a solution to this issue? thank you 🙏

pzatorski commented 9 months ago

This is still an issue.

@eric-everbright I wrote my own Modal component in use of react-native-portal and react-native-reanimated library.

TheAdamBorek commented 8 months ago

We also encountered the issue. Here's a pseudo-code:

<Modal>
    <NavigationContainer independent>
        <Stack.Navigator>
            <Stack.Screen [...] />
        </Stack.Navigator>
    </NavigationContainer
</Modal> 

Our workaround was to set detachInactiveScreens to false. We think this stops React Navigation from using react-native-screens as an optimization.

Unfortunately, this is a workaround and it's only available on Stack Navigator, not on Native Stack Navigator.

kkafar commented 5 months ago

Yeah, took a look.

We (in react-native-screens) assume that NavigationContainer (ScreenStack on native side) is attached under ReactRootView, otherwise we throw an native exception - the one you see.

Looks like react-native's Modal is not presented using any Fragment, it is just pure Dialog. Therefore even when I adjusted the code to not crash when presented under separate DecorView w/o ReactRootView higher in hierarchy it turned out as I expected, that neither application's supportFragmentManager, nor any other FragmentManager associated with Fragment mounted under "original" DecorView can be used, due to how FragmentManager works - basically in various algorithms for finding views it uses internally it traverses only the view tree it resides in, not taking into account that there might be other DecorViews (with different view trees) present, basically leading to another crash.

ScreenContainer must have access to fragment manager, otherwise it is not able to perform any transactions (view mounting / unmounting). Therefore, when presented in modal context it needs to live inside a Fragment. Application's supportFragmentManager can not be used due to reasons explained above, thus only solution I see is to show react-native's modal in context of DialogFragment, which requires changes in react-native (doable & will note this down).

Alternative would be to wait for #2045, which shall introduce native modals controlled by this library.

If you have any idea of different way for solving this, let me know.

kkafar commented 4 months ago

I'm revisiting this issue with thoughts that we won't be able to solve this particular issue on the library side, thus I'll close it. However I do leave discussion unlocked, if there is any breakthrough don't hesitate to ping me.

grahammendick commented 4 months ago

The Navigation router's stack works inside a React Native modal. You can try it out in the medley sample. It uses a FragmentManager under the supportFragmentManager.

kkafar commented 4 months ago

You motivate me @grahammendick

grahammendick commented 4 months ago

That's great. If you've any questions I'll do my best to help