forked from software-mansion/react-native-screens
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(iOS): Crash while pushing n different screens at the same time (s…
…oftware-mansion#2249) ## Description On Paper, while user tries to navigate to 2 or more screens at the same time, updates were batched (on async thread), resulting rerendering stack hierarchy on the next layout. In the same scenario, on Fabric, updates are not being batched, which causes crash: ``` "<RNSNavigationController> is pushing the same view controller instance (<RNSScreen>) more than once which is not supported and is most likely an error in the application" ``` since `maybeAddToParentAndUpdateContainer` is being called to early. This PR fixes this bug by moving the logic of calling that method on `mountingTransactionDidMount` method. I've also checked if this change does not call `maybeAddToParentAndUpdateContainer` too frequent and I can't see more than one correct call there (every doubled call is being catched by `return` in conditions). Fixes software-mansion#2235. ## Changes - Moved updating containers to `mountingTransactionDidMount` method. ## Screenshots / GIFs ### Before https://github.com/user-attachments/assets/24daf575-d06c-4972-9166-89454be60126 ### After https://github.com/user-attachments/assets/d377c527-0b2c-4850-b0b5-8e93dd5f25ac ## Test code and steps to reproduce You can use `Test2235.tsx` to test this change. ## 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]>
- Loading branch information
Showing
3 changed files
with
134 additions
and
7 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,107 @@ | ||
import React from 'react'; | ||
import { View, StyleSheet } from 'react-native'; | ||
import { | ||
createNativeStackNavigator, | ||
NativeStackNavigationProp, | ||
} from '@react-navigation/native-stack'; | ||
import { Button } from '../shared'; | ||
import { NavigationContainer, ParamListBase } from '@react-navigation/native'; | ||
|
||
interface RouteProps { | ||
navigation: NativeStackNavigationProp<ParamListBase>; | ||
} | ||
|
||
const MainScreen = ({ navigation }: RouteProps): React.JSX.Element => ( | ||
<View style={{ ...styles.container, backgroundColor: 'moccasin' }}> | ||
<Button | ||
title="Push 2 screens at once" | ||
onPress={() => { | ||
navigation.navigate('Detail'); | ||
navigation.navigate('Detail2'); | ||
}} | ||
/> | ||
<Button | ||
title="Open nested stack" | ||
onPress={() => { | ||
navigation.navigate('NestedStack'); | ||
}} | ||
/> | ||
</View> | ||
); | ||
|
||
const NestedMainScreen = ({ navigation }: RouteProps): React.JSX.Element => ( | ||
<View style={{ ...styles.container, backgroundColor: 'moccasin' }}> | ||
<Button | ||
title="Go to detail" | ||
onPress={() => { | ||
navigation.navigate('Detail'); | ||
navigation.navigate('Detail2'); | ||
}} | ||
/> | ||
<Button | ||
title="Pop stack" | ||
onPress={() => { | ||
navigation.goBack(); | ||
}} | ||
/> | ||
</View> | ||
); | ||
|
||
|
||
const DetailScreen = ({ navigation }: RouteProps): React.JSX.Element => ( | ||
<View style={{ ...styles.container, backgroundColor: 'thistle' }}> | ||
<Button | ||
title="Go back" | ||
onPress={() => navigation.goBack()} | ||
/> | ||
</View> | ||
); | ||
|
||
const DetailScreen2 = ({ | ||
navigation, | ||
}: RouteProps): React.JSX.Element => ( | ||
<View style={{ ...styles.container, backgroundColor: 'yellow' }}> | ||
<Button | ||
title="Go back" | ||
onPress={() => navigation.goBack()} | ||
/> | ||
</View> | ||
); | ||
|
||
const NestedStackScreen = (): React.JSX.Element => ( | ||
<NestedStack.Navigator screenOptions={{ headerBackVisible: false }}> | ||
<NestedStack.Screen name="NestedDetail" component={NestedMainScreen} /> | ||
<Stack.Screen name="Detail" component={DetailScreen} /> | ||
<Stack.Screen name="Detail2" component={DetailScreen2} /> | ||
</NestedStack.Navigator> | ||
) | ||
|
||
const Stack = createNativeStackNavigator<ParamListBase>(); | ||
const NestedStack = createNativeStackNavigator<ParamListBase>(); | ||
|
||
const App = (): React.JSX.Element => ( | ||
<NavigationContainer> | ||
<Stack.Navigator | ||
screenOptions={{ | ||
headerBackVisible: false, | ||
}}> | ||
<Stack.Screen | ||
name="Main" | ||
component={MainScreen} | ||
options={{ title: 'Simple Native Stack' }} | ||
/> | ||
<Stack.Screen name="Detail" component={DetailScreen} /> | ||
<Stack.Screen name="Detail2" component={DetailScreen2} /> | ||
<Stack.Screen name="NestedStack" component={NestedStackScreen} /> | ||
</Stack.Navigator> | ||
</NavigationContainer> | ||
); | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
paddingTop: 10, | ||
}, | ||
}); | ||
|
||
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