Drawer navigation screen broken, after parent state has changed - react-native

When I change state from custom bottom bar (Parent root's state), screen looks weird. I don't catch my mistake.
Does parent screen's state affect on the child screens width?
const [loggedUser, setLoggedUser] = useState<any>();
<NavigationContainer
ref={navigationRef}>
{loginState?.loginToken === null ? (
<AuthStackScreens />
) : (
<AppContainer />
)}
</NavigationContainer>
AppContainer's structure looks like this.
- Stack.Navigator
- Drawer.Navigator
- Stack Navigation 1 (Tabbar: Custom bottom bar)
- Contact
- Others ...
- Stack Navigation 2
- ...
- ...
- ...
I hope you guys suggest me solution.

Related

display a view above a react nativigation modal

I have a custom snackbar component which has a zIndex higher than other views and an absolute position in the app.
The snackbar works fine, as long as no modals are opened. The problem is, I have nested navigation with nested modals and the snackbar component needs to be on top, all the time.
currently, my screenOptions are: { presentation: 'modal' }
Others like containedModal work, but gives me stacked headers for all the parent modals. I like the way modal presentation looks on iOs. Any ideas how an absolute View can be displayed above any modal from the root of the app?
Z-index in RN doesn't work the same as it does on web - see the docs for more. Components are rendered as a tree, with the first items on the bottom and stacking until the last items are on top.
Therefore you can put a component on top of everything else by rendering it outside and after everything else. I.e.
// App.js
const App = () => {
return (
<>
<NavigationContainer>
<MainStack />
</NavigationContainer>
<Snackbar />
</>
);
};

Navigate from inner navigator to outer navigator generate extra screen slide

I have a problem during the logout in my react native app. I set many navigators to handle multiple navigation flow, but when I try to logout from the app, the login screen appears two times.
I try to explain how I organize my navigators below:
I created a TabNavigator which handle the main navigation of the app if a user is logged in otherwise I show the LoginNavigator which handle login, registration and password forgot screens.
I use a state, stored on redux for handling the login state (isLoggedIn).
<NavigationContainer>
{isLoggedIn ? <TabNavigator/> : <LoginNavigator/>}
</NavigationContainer>
Into the TabNavigator I set other navigator for handling page flow in each sections, like the exemple below:
TabNavigator
Screen X
Navigator1
Screen A
Screen B
Navigator2
Screen C
Screen D
Screen Y
Into the Screen C I'd like to logout from the app, so I call an action which set the isLoggedIn state to false.
What happens is that the Login screen (the inital screen of LoginNavigator) appears, but it suddently slides off and another Login screen appears.
It happens only from nested screen, instead if I try to logout from Screen X or Screen Y it works perfectly fine.
Does anyone encounter this problem? How can I solve this behaviour?
I solved this behaviour!
Instead of showing the correct navigator using a ternary operation, base on redux state, I wrap TabNavigator and LoginNavigator inside a custom stack navigator with a WaitingScreen.
I set the WaitingScreen as inital route and I moved the logic about which route between MainNavigator and LoginNavigator has to be shown inside WaitingScreen, in a useLayouEffect with isLoggedIn as dependecy.
<NavigationContainer>
<Stack.Navigator
initialRouteName={NavConst.LOADING}
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor: Color.primary600,
},
animation: "none",
}}
>
<Stack.Screen name={NavConst.LOADING} component={WaitingScreen} />
<Stack.Screen name={NavConst.LOGIN_NAV} component={LoginNavigator} />
<Stack.Screen name={NavConst.MAIN_NAV} component={MainNavigator} />
</Stack.Navigator>
</NavigationContainer>
and inside the WaitingScreen:
useLayoutEffect(() => {
isLoggedIn
? navigation.navigate(NavConst.MAIN_NAV);
: navigation.navigate(NavConst.LOGIN_NAV);
}, [isLoggedIn]);

React-navigation v6: Custom tab bar not navigating between screens on Android

I can't seem to figure out what is causing this code to not work on Android. It works well on iOS. It is a custom tab bar which lives inside a screen of the "normal" bottom tab bar. It has three screens and when switching between them I can see that things are happening under the hood, it's just that only the last tab screen is shown. All of the screens are being rendered and using useFocusEffect I can see that the screens are getting focused when the buttons are pressed, but they are not shown. So it's like they´re hidden behind the last tab screen.
The code is pretty much exactly taken from the example in the react-navigation guide (and I have also tried this with the exact example code):
https://reactnavigation.org/docs/custom-navigators
except that the top level <view>s had to switch places for the tab bar to be visible.
The tab navigator is then embedded like this (I have just replaced the actual names with numbers):
const 4Tab = createCustomTabNavigator<4ParamList>()
export default function 4TabNavigator() {
return (
<4Tab.Navigator initialRouteName="1">
<4Tab.Screen name="1" component={1Navigator} />
<4Tab.Screen name="2" component={2Navigator} />
<4Tab.Screen name="3" component={3Navigator} />
</4Tab.Navigator>
)
}
which in turn is embedded like so (4TabNavigator):
const Tab = createBottomTabNavigator() // Normal tab bar
const TabStack: React.FC<Props> = props => {
return (
<Tab.Navigator
initialRouteName={TabRouteName.1}
screenOptions={tabScreenOptions}>
<Tab.Screen name={TabRouteName.1} component={1Navigator} />
<Tab.Screen name={TabRouteName.2} component={2Navigator} />
<Tab.Screen name={TabRouteName.3} component={3Stack} />
<Tab.Screen
name={TabRouteName.4}
component={4TabNavigator}
options={{ lazy: true }}
/>
<Tab.Screen name={TabRouteName.5} component={5Navigator} />
</Tab.Navigator>
)
}
I'm not sure if this is an issue with react-navigation at all, but I also don't know what else could be wrong. I have looked through react-navigation's GitHub issues, and of course here on SO, but to no avail.

How to prevent image rerender on each screen navigate?

Im using react-navigation on my rect-native app. I have a custom header component with a logo image in it -
<Container key="app-header" {...props}>
...
<LogoMemo opacity={logoInvisible ? 0 : 1} />
...
</Container>
The logo component is a pure component -
const Logo = ({opacity}) => {
const src = require('../assets/header-logo.png');
return (
<Image
source={src}
resizeMode="contain"
style={[styles.bigLogo, {opacity}]}
/>
);
};
Logo.whyDidYouRender = true;
const LogoMemo = React.memo(Logo);
But still, the Logo is rerendering on each screen navigation, which cause image flickering.
I think it is because every screen have his own Header.js component. So if the parent (WhateverScreen.js) is rerendering - all its children are rerendered too. Is there a way to Prevent the Logo from rerendering?
Thankss

How to disable swipe action in specific screen on react navigation 5?

im using react navigation 5 on my project, and somewhere in the project i need to make nested navigators like below:
*Stack Navigator
**Material top tab navigatior
***Material bottom tab navigator
**** Stack Navigator
My goal is, actually i want to have 3 static screens like instagram. On the left side will be Camera, then in the center actual content and in the right side something else. And only when you are in center i want to bottom tabs are visible thats why i created it like that. In this case in all the screens you can swipe right or left for reaching to camera or right component.
But what i want to do is, i want do "disable" swipe action in detail screens in center component. Becose center component which is material bottom tab navigator above, contains some stack navigators also, like posts, postDetail. and when i go to postDetail i want to disable swipe left or right action. Becouse in some details im using some swipeable elements like react native swiper etc.
I have tried to give gesturesEnabled: false , swipeEnabled: false in material bottom navigator as props but it doesn't work becouse it's a bottom tab navigator and doesn't take these params.
I also tried to catch state index and if its greater than 0 or 1 i would disable it but in material top tab navigator doesn't change the index when i go to postDetail for example. It's not working like previous version which is react navigation 4.
const BlogStack = createMaterialTopTabNavigator();
const BlogStackNavigator = ({ navigation, route }) => {
return (
<BlogStack.Navigator
initialRouteName="Blogs"
tabBarOptions={{
style: {
height: 0,
},
}}
//swipeEnabled={route.state && route.state.index > 0 ? false : true}
>
<BlogStack.Screen name="Camera" component={Camera} />
<BlogStack.Screen name="Blogs" component={Blog} />
<BlogStack.Screen name="Timeline" component={Profile} />
</BlogStack.Navigator>
);
};
Try setting gestureEnabled to false in Screen's options.
<Screen name={key} options={{gestureEnabled: false}} component={Component} />
You need to set gestureEnabled to false but it's not sent as a prop. You need to set it in the options prop. If you want to set it for all screens you can place it in the navigator like this:
<BlogStack.Navigator
initialRouteName="Blogs"
tabBarOptions={{
style: {
height: 0,
},
}}
screenOptions={{gestureEnabled: false}}
>
or for only specific screens:
<BlogStack.Screen name="Camera" options={{gestureEnabled: false}} component={Camera} />