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

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.

Related

How can I navigate from login screen to a bottomtab screen?

How can I navigate to a bottomtab screen rather than a stack screen? The goal is to take the user to the main home page onPress of the sign in button. I initially created a Stack.Screen and added the homescreen component but that crashed the header and the bottom tab navigation and there was also the back button in the header which isn't supposed to be because the home screen is the main screen. Is there a way to navigate to the bottom tab screen from the sign in component? I'm a beginner by the way and also not so good at using stack overflow
if you're using react router than this may possible with useNavigate() and Link. Also you can add custom javascript window.location.href ="/pagename"
Usage of useNavigate() before return of function-
const navigate = useNavigate()
onClick = (e)=>(
e.preventDefault()
navigate('/home')
)
Usage of Link inside body-
<Link to="/home"></Link>
Usage of custom javascript inside body-
<button onClick = (()=>window.location.href="/home"))>Click me</button>
Hope you'll like the answer. But if you still face any issue just lemme know.
I suggest you to try an Authentication flow approch written by 'React-Navigator' API.
The main idea of that is using 2 Navigators.
Stack Navigator for 'Login'
Tab Navigator for pages which logged in users can see
However, to make this flow available, you need to add Global State Management library like Redux / React Context to handle which navigator is showing. Once the state is set, the app will auto select the navigator used. You don't need to call any function for navigation.
<NavigationContainer>
<Stack.Navigator>
{
!redux.isLoggedIn ?
<Stack.Group>
<Stack.Screen
name="auth"
component={Auth}
/>
</Stack.Group>
:
<Stack.Group>
<Stack.Screen
name="home"
component={YourHomeTabNavigator}
/>
</Stack.Group>
}
</Stack.Navigator>
</NavigationContainer>

react-native-navigation: set screen as root parent

I'm using react-native-navigation with:
a custom animated app loading screen
my home screen
I created a Stack.Navigator as follows:
<Stack.Navigator
initialRouteName="AnimatedAppLoader"
>
<Stack.Screen
name="AnimatedAppLoader"
component={AnimatedAppLoader}
/>
<Stack.Screen
name="Home"
component={Home}
/>
</Stack.Navigator>
My AnimatedAppLoader waits that the app is ready then navigate to the Home screen through:
navigation.navigate('Home');
The problem is that the Home screen becomes a child of AnimatedAppLoader screen and users can go back to the loader screen.
I tried to disable back button and back gestures but this solution does not seem proper since android users can still go back with the system back button.
Is there a proper way to set my Home screen as the root parent of my app?
use navigation.replace('Home'); replace will replace the current screen with a new one rather than adding a new screen
you can read more at the props
https://reactnavigation.org/docs/navigation-prop/

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]);

Hidding custom tabbar in nested stack navigation

I have a tabbar looking like the one below. inside every tab I have a nested stack navigator.
I want to hide the tabbar whenever the stack is not on its initial route. In the documentation, it is stated like one is supposed to place the stack in the initial stack navigator.
https://reactnavigation.org/docs/hiding-tabbar-in-screens/
However, this does not make sense and as I have my signup and all the routes where the customer is not logged in there I think it is counter-intuitive to place the entire application in one stack navigator. Further, it diminishes the purpose of having a tab-navigation in the first place.
I have also tried the tabBarVisible prop and change this conditionally. However, this provides me with some issues.
First, it does not seem to work on mu custom tabBar. Further, it gives me the state of every tab for every render. Thus it causes some unwanted behavior. lastly, it is not recommended from the documentation.
<Tab.Navigator
tabBar={props => (
<TabBar
onPress={tabIndex => changeTab(tabIndex, props)}
display={false}
values={[
{ title: "Balance", icon: 'view-dashboard'},
{ title: "Faktura", icon: 'file-pdf'},
{ title: "Rabatter", icon: 'gift'},
{ title: "Profil", icon: 'account-details'},
{ title: "Mere", icon: 'dots-horizontal' }
]}/>
)}>
<Tab.Screen
name="Balance"
component={BalanceStackNavigator}
/>
<Tab.Screen
name="Invoice"
component={InvoiceStackNavigator}
/>
<Tab.Screen
name="BlueBenefit"
component={BlueBenefitStackNavigator}
/>
<Tab.Screen
name="User"
component={UserStackNavigator}
/>
<Tab.Screen
name="CrossSale"
component={CrossSaleStackNavigator}
/>
</Tab.Navigator>
So basically my question is, how I achieve this behavior of hiding the tabs when not on the initial route in the best way?
I ended up using what was recommended by the documentation, which is to place all of my screens in my app stack instead of the individual nested stacks.

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} />