From c5cd87a1c9d228029e64e0bfb7cf3ea5b4ed2b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Du=C5=BCy?= <91994767+alduzy@users.noreply.github.com> Date: Tue, 9 Jul 2024 09:55:52 +0200 Subject: [PATCH] fix(iOS): white flash on tab change when using native stack (#2188) This PR gets rid of undesired white flashes during `maybeAddToParentAndUpdateContainer`. The white flash was present on paper architecture when `unmountOnBlur` option was set to true on parent bottomStackNavigator (see repro). The affected logic was previously introduced or changed by following PRs: - https://github.com/software-mansion/react-native-screens/pull/600 - https://github.com/software-mansion/react-native-screens/pull/613 - https://github.com/software-mansion/react-native-screens/pull/643 The removed `_hasLayout` was initially added by https://github.com/software-mansion/react-native-screens/pull/600 in order to resolve an issue: https://github.com/software-mansion/react-native-screens/issues/432. However the logic was later changed by https://github.com/software-mansion/react-native-screens/pull/613 in order to fix another issue and the added `_hasLayout` may not fix anything eventually, as stated by [this comment](https://github.com/software-mansion/react-native-screens/issues/432#issuecomment-687868469). Fixes #1645. - removed `_hasLayout` variable - added repros https://github.com/software-mansion/react-native-screens/assets/91994767/226a32d7-728b-48dd-b21a-6a1e4195add2 https://github.com/software-mansion/react-native-screens/assets/91994767/32febcf1-d159-4a9d-ae3a-373042732a6d - added `Test1645.js` repro to test examples - added `Test432.tsx` repro to test examples - [x] Included code example that can be used to test this change - [x] Ensured that CI passes --------- Co-authored-by: Kacper Kafara --- apps/src/tests/Test1645.js | 98 ++++++++++++++++++++++++++++++++++++++ apps/src/tests/Test432.tsx | 72 ++++++++++++++++++++++++++++ apps/src/tests/index.ts | 2 + ios/RNSScreenStack.mm | 18 ++----- 4 files changed, 175 insertions(+), 15 deletions(-) create mode 100644 apps/src/tests/Test1645.js create mode 100644 apps/src/tests/Test432.tsx diff --git a/apps/src/tests/Test1645.js b/apps/src/tests/Test1645.js new file mode 100644 index 0000000000..ec4a508944 --- /dev/null +++ b/apps/src/tests/Test1645.js @@ -0,0 +1,98 @@ +/* eslint-disable react-native/no-inline-styles */ + +import React, {useEffect, useState} from 'react'; +import {Text, View} from 'react-native'; + +import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; +import {createNativeStackNavigator} from '@react-navigation/native-stack'; +import {createStackNavigator} from '@react-navigation/stack'; +import {NavigationContainer} from '@react-navigation/native'; + +const TestBottomTabBar = createBottomTabNavigator(); +const TestNativeStack1 = createNativeStackNavigator(); +const TestNativeStack2 = createNativeStackNavigator(); + +const TestScreen1 = () => { + const [t, setT] = useState(110); + + useEffect(() => { + const interval = setInterval(() => { + setT(lastT => lastT + 1); + }, 100); + + return () => clearInterval(interval); + }, []); + return ( + + {Array.from({length: 100}).map((e, idx) => ( + + T{idx}: {t} + + ))} + + ); +}; + +const TestScreen2 = () => { + const [t, setT] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setT(lastT => lastT + 1); + }, 100); + + return () => clearInterval(interval); + }, []); + + return ( + + {Array.from({length: 100}).map((e, idx) => ( + + T{idx}: {t} + + ))} + + ); +}; +const TestScreenTab1 = () => { + return ( + + + + + ); +}; + +const TestScreenTab2 = () => { + return ( + + + + + ); +}; + +const App = () => { + return ( + + + + + + + ); +}; + +export default App; diff --git a/apps/src/tests/Test432.tsx b/apps/src/tests/Test432.tsx new file mode 100644 index 0000000000..5a0843dbc0 --- /dev/null +++ b/apps/src/tests/Test432.tsx @@ -0,0 +1,72 @@ +import { Pressable, View, Button, Text } from 'react-native'; + +import { NavigationContainer, useNavigation } from '@react-navigation/native'; +import { + NativeStackScreenProps, + createNativeStackNavigator, +} from '@react-navigation/native-stack'; +import React, { useCallback } from 'react'; + +type RootStackParamList = { + Home: undefined; + Settings: undefined; +}; +type RootStackScreenProps = + NativeStackScreenProps; +const HomeScreen = ({ navigation }: RootStackScreenProps<'Home'>) => { + const showSettings = useCallback(() => { + navigation.navigate('Settings'); + }, [navigation]); + return ( + +