software-mansion / react-native-screens

Native navigation primitives for your React Native app.
MIT License
3.01k stars 510 forks source link

[iOS] bug with @react-navigation/bottom-tabs - initial jumping #1251

Open hirbod opened 2 years ago

hirbod commented 2 years ago

Description

When using @react-navigation/bottom-tabs with RNS, the content jumps on tab change (one the first render only). I made sure I've tested this plenty of times.

The bug does not occur if I import

import { createStackNavigator } from '@react-navigation/stack';

but with

import { createNativeStackNavigator } from '@react-navigation/native-stack';

My whole is wrapped with SafeAreaProvider from react-native-safe-area-context like so:

import {
  SafeAreaProvider,
  initialWindowMetrics
} from 'react-native-safe-area-context';
        <SafeAreaProvider initialMetrics={initialWindowMetrics}>
            <Navigator theme={combinedTheme} />
        </SafeAreaProvider>

I also tried to test it without initialMetrics and also used SafeAreaView(from react-native-safe-area-context and react-native), but it still jumped for me.

I also patched react-navigation bottoms tabs with this PR applied by @WoLewicki https://github.com/react-navigation/react-navigation/pull/9772

But the jump still occur. Also made sure to disable/enable freeze etc. I couldn't manage to prevent the initial jumping. See my video attached.

Screenshots

I created a dead simple preview, see my Video below. Please watch the in the center. https://streamable.com/i7upqv

Expected behavior

Should not jump on initial render

Actual behavior

It jumps on initial render and it does look weird

Reproduction

Happens on iOS, snack not helping here.

Platform

Workflow

Package versions

package version
react-native 0.64.3
@react-navigation/native 6.0.6
@react-navigation/native-stack 6.2.5
react-native-screens 3.10.1
react-native-safe-area-context 3.3.2
react-native-gesture-handler 2.1.0
react-native-reanimated 2.3.1
expo 44.0.3
  Expo CLI 5.0.3 environment info:
    System:
      OS: macOS 11.6.1
      Shell: 5.8 - /bin/zsh
    Binaries:
      Node: 14.18.2 - /usr/local/opt/node@14/bin/node
      Yarn: 1.22.17 - /usr/local/bin/yarn
      npm: 6.14.15 - /usr/local/opt/node@14/bin/npm
      Watchman: 2021.12.06.00 - /usr/local/bin/watchman
    Managers:
      CocoaPods: 1.11.2 - /usr/local/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 21.2, iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3
    IDEs:
      Android Studio: 4.1 AI-201.8743.12.41.6953283
      Xcode: 13.2.1/13C100 - /usr/bin/xcodebuild
    npmPackages:
      react-dom: 17.0.2 => 17.0.2 
      react-native-web: 0.17.5 => 0.17.5 
    npmGlobalPackages:
      eas-cli: 0.41.1
      expo-cli: 5.0.3
    Expo Workflow: bare
hirbod commented 2 years ago

P.S: I thought this is the right repo to post this issue. If you feel I have to post this at react-navigation, let me know.

WoLewicki commented 2 years ago

Can you post this simple repo with the changed applied with e.g. patch-package so we can work on it?

hirbod commented 2 years ago

@WoLewicki I got rid of it with headerTransparent:true + remove of initialMetrics and some refactoring of my navigators, but I still think that this is bug, because it does not work with all combinations.

WoLewicki commented 2 years ago

Hmm if you think this is a bug on react-native-screens side, please provide a reproduction so we can work on it.

hirbod commented 2 years ago

@WoLewicki I will provide a reproduction soon. I think it is indeed a bug on rns.

pt7892 commented 2 years ago

@WoLewicki

Here is repo with reproduced bug: https://github.com/pt7892/rnscreens-bottom-tab-flicker

also videos:

https://user-images.githubusercontent.com/20343932/151573753-31677bc2-078f-4697-8fe5-ed64f1f3e1aa.mp4

https://user-images.githubusercontent.com/20343932/151573647-f13466e2-cbf4-4080-bb08-7355ca1c4255.mov

If initial tab screen is simple, you may not notice this, thats why i added bunch of Text and Button components

From what i understand, on tab change, if stack is being mounted first time, 2 RNScreen are being layout on screen, but not in same "tick", and thats why you may notice this flash effect

WoLewicki commented 2 years ago

@pt7892 is the jumping behavior connected to the flicker issue you posted here?

pt7892 commented 2 years ago

@WoLewicki

Actually, i was referring to this issue GH-1276, but mistakenly added comment on this one.

I see now that reproduction repo is already uploaded in GH-1276, so this comment can be deleted.

Sorry for the mistake

vladyslavNiemtsev commented 2 years ago

I also have the similar issue. But it happens not only in Initial rendering. It happens every time when I go or come back to the screen inside BottomTabNavigator.

My packages:

"@react-navigation/bottom-tabs": "^6.2.0", "@react-navigation/elements": "^1.3.1", "@react-navigation/material-top-tabs": "^6.1.1", "@react-navigation/native": "^6.0.8", "@react-navigation/native-stack": "^6.5.0", "react-native-reanimated": "^2.4.1", "react-native-safe-area-context": "^3.3.2", "react-native-screens": "3.11.0",

vladyslavNiemtsev commented 2 years ago

@hirbod Do you have a workaround for it?

WoLewicki commented 2 years ago

@vladyslavNiemtsev please provide a reproduction of this issue then so we can work on it, otherwise we cannot do much about it.

vladyslavNiemtsev commented 2 years ago

hey, when I set headerTransparent: true as described here: https://github.com/software-mansion/react-native-screens#solution The problem with jumping is gone on Android.

But I still have a problem with content cut off on Android.

WoLewicki commented 2 years ago

I think this issue was about iOS, so I am not sure what issue you are mentioning. Or am I missing something?

hirbod commented 2 years ago

He is indeed right. It is also jumping on android. Only headerTransparent was helping for me

hukpo commented 2 years ago

Just a small point here, if you have headerShown: false in your BottomTabNavigator when you enable it - jumping disappears

hirbod commented 2 years ago

@WoLewicki this is still a thing. The issue comes from where you add headerShown or headerTranslucent.

If you use the header provided by BottomTab, there is no jumping. But when you have a nested stack as a tab, you don't want to use the header from the BottomTab, instead you wan't to use the header provided by the nested stack.

This jumping is still super annoying and there is no real way around it. It just looks like the insets where applied too late and thats what cause the drops. There are repos available in the issue tracker, there is even a duplicated issue: https://github.com/software-mansion/react-native-screens/issues/1276

Would be awesome if we could resolve this.

WoLewicki commented 2 years ago

I tried to debug and solve this some time ago but I did not manage to find a solution. If you have any time frame to debug it, it would be really helpful.

l0gicgate commented 2 years ago

Iā€™m experiencing the same issue. It seems to be related to the headerShown option. It only happens on first render as well.

With headerShown: false: https://user-images.githubusercontent.com/6510935/173461630-7ddb650d-5ee6-41c0-80de-fa1b8a8fea0d.MOV

With headerShown: true: https://user-images.githubusercontent.com/6510935/173461690-78c17f4b-0481-44c2-a100-dc724a1eabe2.MOV

I found a workaround for this. Instead of using SafeAreaView you will need to style a View component and use the useSafeAreaInsets hook to set the appropriate padding:

import { useSafeAreaInsets } from 'react-native-safe-area-context';
import PropTypes from 'prop-types';
import styled from 'styled-components/native';

const StyledView = styled.View`
  background-color: black;
  flex: 1;
  padding-bottom: ${({ insets }) => insets.bottom}px;
  padding-top: ${({ insets }) => insets.top}px;
`;

export const SafeAreaView = ({ children, ...otherProps }) => {
  const insets = useSafeAreaInsets();
  return (
    <StyledView {...otherProps} insets={insets}>
      {children}
    </StyledView>
  );
};

SafeAreaView.propTypes = {
  children: PropTypes.node,
};

SafeAreaView.defaultProps = {
  children: null,
};
pjc0247 commented 2 years ago

useSafeAreaInsets works for me

sjransom commented 2 years ago

Fixed this by swapping <SafeAreaView /> with useSafeAreaInsets()

<View style={[styles.container, { paddingTop: Math.max(insets.top, 16) }]} {...otherProps}>

l0gicgate commented 2 years ago

@sjransom see my comment here

You cannot use SafeAreaView, you have to create a regular View component and use the useSafeAreaInsets() to pad it appropriately.

aymather commented 2 years ago

I've tried using the custom View with useSafeAreaInsets() and I've also tried not using any SafeAreaView at all, and I'm still getting the glitching effect :(

l0gicgate commented 2 years ago

@aymather please show the smallest reproducible example possible

aymather commented 2 years ago

@l0gicgate Ok so I've tried reproducing the problem... and of course... no dice... but I have recreated a very basic environment to demonstrate a working concept if anyone wants to view it / try to reproduce the problem from there. Here is the repository. (I'll also just add that this environment was created with npx react-native init [name])

I did, however, fix the problem in my app by upgrading react-native-screens from 3.12.0 -> 3.3.0.

Now... I thought that the version might have something to do with the problem, so when I first tried to reproduce the problem, the version that came in when i added react-native-screens was 3.15.0 and the issue wasn't there. So I thought, oh ok.. it was probably something that was patched. So I then downgraded from 3.15.0 -> 3.12.0 to try to reproduce the problem. However, even after downgrading, I still was unable to get the glitch to happen...

For anyone who is still facing this issue, I'd say try removing the package from your project completely, and reinstalling it. Try the 3.3.0 version and see if that works too. Maybe a good-ole-fashioned rm -rf node_modules && rm yarn.json && yarn is all that's needed..? šŸ¤·šŸ»ā€ā™‚ļø

Rebsos commented 2 years ago

Any update on this? Can we have something like "headerTopInsetEnabled" from React Navigation V5 back?

Edit: After wrapping my App with <SafeAreaProvider><App/></SafeAreaProvider> from react-native-safe-area-context it does not jump anymore (no more double height header for a sec).

github-actions[bot] commented 2 years 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?

brandon-austin-lark commented 1 year ago

I'm currently experiencing this issue. Tried all of the solutions above and no luck.

Sumit2202 commented 1 year ago

Any update on the above issue?

anhquan291 commented 1 year ago

Facing the same issue!

elmaxe commented 7 months ago

Faced the same issue today

https://github.com/software-mansion/react-native-screens/issues/1251#issuecomment-1154533585

This solution worked