-
-
Notifications
You must be signed in to change notification settings - Fork 547
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(Paper,iOS): dismiss all attached view controllers correctly on re…
…load (#2175) ## Description This PR addresses an issue with react-native-screens where modals were not being dismissed correctly during app reloads when combined with foreign view controllers. The fix involves enhancing the invalidate method to recursively dismiss all presented view controllers, ensuring a clean state on reload. This is not a development-only problem; this fix also addresses reloads from OTA updates. ## Changes - Enhanced invalidate method in RNSScreenStack.mm to recursively dismiss all presented view controllers. - Ensured _presentedModals is cleared and _controller is detached from its parent during invalidation. - Added a helper method dismissAllPresentedViewControllersFrom to handle recursive dismissal logic. ## Screenshots / GIFs | Before | After | |--------|--------| | <video width="320" height="240" controls src="https://github.com/software-mansion/react-native-screens/assets/504909/1476ab3a-4bd9-4ffa-9256-760467a108bc"></video> | <video width="320" height="240" controls src="https://github.com/software-mansion/react-native-screens/assets/504909/e6c5eef0-16c6-49a2-9124-86467feec7f2"></video> | The red background is from a `transparentModal` by RNS, the sheet is a foreign view controller. Before the change, `react-native-screens` would break on reload if a foreign view controller was mounted on top. I came to the solution after finding [this PR](#2113). The issue originally started [here](lodev09/react-native-true-sheet#34). After my changes, RNS works correctly on reload with third-party controllers. I have no experience with Fabric, so I can't help with that. Feel free to update the solution for Fabric if needed. ## Test code and steps to reproduce Test2175 ## Checklist - [x] Included code example that can be used to test this change - [x] Ensured that CI passes --------- Co-authored-by: Kacper Kafara <[email protected]> Co-authored-by: adrianryt <[email protected]>
- Loading branch information
1 parent
437f6ea
commit 88d9794
Showing
4 changed files
with
172 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import React from 'react'; | ||
import { Button, Modal, SafeAreaView, Text, View } from 'react-native'; | ||
|
||
import { createNativeStackNavigator } from '@react-navigation/native-stack'; | ||
import { NavigationContainer } from '@react-navigation/native'; | ||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; | ||
|
||
const Stack = createNativeStackNavigator(); | ||
const Tabs = createBottomTabNavigator(); | ||
|
||
|
||
function TabScreens({ navigation }): React.JSX.Element { | ||
return ( | ||
<Tabs.Navigator> | ||
<Tabs.Screen name='A' component={HomeScreen} /> | ||
<Tabs.Screen name='B' component={TabHomeScreen} /> | ||
</Tabs.Navigator> | ||
); | ||
} | ||
|
||
function TabHomeScreen({ navigation }): React.JSX.Element { | ||
return ( | ||
<View style={{ flex: 1, backgroundColor: 'lightcoral', justifyContent: 'center', }}> | ||
<Text>Where do you where do you go, my lovely, oh oh oh oh</Text> | ||
<Button title='Show owned transparentModal (outer navigator)' onPress={() => { navigation.navigate('TransparentModal') }} /> | ||
<Button title='Show owned modal (outer navigator)' onPress={() => { navigation.navigate('Modal') }} /> | ||
</View> | ||
) | ||
} | ||
|
||
|
||
function HomeScreen({ navigation }): React.JSX.Element { | ||
const [toggle, setToggle] = React.useState(false); | ||
return ( | ||
<View style={{ flex: 1, backgroundColor: 'lightseagreen', justifyContent: 'center', }}> | ||
<Text>Where do you where do you go, my lovely, oh oh oh oh</Text> | ||
<Button title='Show owned transparentModal' onPress={() => { navigation.navigate('TransparentModal') }} /> | ||
<Button title='Show owned modal' onPress={() => { navigation.navigate('Modal') }} /> | ||
<Button title='Show tabs' onPress={() => { navigation.navigate('Tabs') }} /> | ||
<Button title='Show foreign modal' onPress={() => { setToggle(old => !old) }} /> | ||
<Modal | ||
visible={toggle} | ||
onRequestClose={() => setToggle(false)} | ||
presentationStyle='formSheet' | ||
animationType='slide' | ||
> | ||
<View style={{ flex: 1, backgroundColor: 'lightblue' }}> | ||
<Text>Hello I'm a foreign modal</Text> | ||
<Button title='Close foreign modal' onPress={() => { setToggle(false) }} /> | ||
</View> | ||
</Modal> | ||
</View> | ||
) | ||
} | ||
|
||
function ModalScreen({ navigation }): React.JSX.Element { | ||
const [toggle2, setToggle2] = React.useState(false); | ||
|
||
return ( | ||
<View style={{ flex: 1, backgroundColor: 'lightcoral', opacity: 0.4 }}> | ||
<Text>Where do you where do you go, my lovely, oh oh oh oh</Text> | ||
<Button title='Go back' onPress={() => { navigation.goBack() }} /> | ||
<View style={{ width: '100%', height: 50, backgroundColor: 'red' }} /> | ||
<Button title='Push another Modal' onPress={() => { navigation.push('Modal') }} /> | ||
<Button title='Push foreign modal(inside Screen Component)' onPress={() => { navigation.push('ForeignModal')}} /> | ||
<Button title='Push foreign modal' onPress={() => { setToggle2(old => !old )}} /> | ||
<Modal | ||
visible={toggle2} | ||
onRequestClose={() => setToggle2(false)} | ||
presentationStyle='formSheet' | ||
animationType='slide' | ||
> | ||
<View style={{ flex: 1, backgroundColor: 'lightblue' }}> | ||
<Text>Hello I'm a foreign modal</Text> | ||
<Button title='Close foreign modal' onPress={() => { setToggle2(false) }} /> | ||
</View> | ||
</Modal> | ||
</View> | ||
) | ||
} | ||
|
||
function ForeignModal({ navigation }): React.JSX.Element | null { | ||
const [toggle, setToggle] = React.useState(false); | ||
return ( | ||
<Modal | ||
visible={toggle} | ||
onRequestClose={() => setToggle(false)} | ||
presentationStyle='formSheet' | ||
animationType='slide' | ||
> | ||
<View style={{ flex: 1, backgroundColor: 'lightblue' }}> | ||
<Text>Hello I'm a foreign modal</Text> | ||
<Button title='Close foreign modal' onPress={() => { setToggle(false) }} /> | ||
</View> | ||
</Modal> | ||
) | ||
} | ||
|
||
|
||
const TestScreen = ({ navigation }): React.JSX.Element => { | ||
return ( | ||
<SafeAreaView> | ||
<Button | ||
title={ | ||
'Click me and drag around a bit and I should log something still' | ||
} | ||
onPress={() => { | ||
console.log(Date.now()); | ||
}} | ||
/> | ||
<Button | ||
title={'Navigate to modal'} | ||
onPress={() => { | ||
navigation.navigate('Test2'); | ||
}} | ||
/> | ||
</SafeAreaView> | ||
); | ||
}; | ||
|
||
function App(): React.JSX.Element { | ||
return ( | ||
<NavigationContainer> | ||
<Stack.Navigator initialRouteName='Tabs'> | ||
<Stack.Screen name='Tabs' component={TabScreens} options={{ headerShown: false }} /> | ||
<Stack.Screen | ||
name="Home" | ||
component={HomeScreen} | ||
/> | ||
<Stack.Screen | ||
name="TransparentModal" | ||
component={ModalScreen} | ||
options={{ | ||
presentation: 'transparentModal', | ||
}} | ||
/> | ||
<Stack.Screen | ||
name="Modal" | ||
component={ModalScreen} | ||
options={{ | ||
presentation: 'modal', | ||
headerShown: true, | ||
}} | ||
/> | ||
<Stack.Screen name={"ForeignModal"} component={ForeignModal} /> | ||
</Stack.Navigator> | ||
</NavigationContainer> | ||
); | ||
} | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters