React navigation - switch between 2 tab navigation - reactjs

Friends, I tried many times but I could not do it. How can I switch between 2 tab navigation, for example 1. tab navigation become a member and login, 2. tab navigation homepage, settings etc. I was doing it in version 3 but now for some reason I couldn't, thanks to all the friends who helped

here is a quick snippet, i only show one tab navigator's full logic for reference, but the second can follow the same logic.
Using react navigation v5.x.x
It works by nesting navigators in screens
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createStackNavigator } from '#react-navigation/stack';
const HomeTabsNavigator = createBottomTabNavigator();
const HomeTabRenderer = () => {
const initialRouteName = 'Feed';
const initialRouteParams = {};
return (
<HomeTabsNavigator.Navigator
initialRouteName={initialRouteName}
initialRouteParams={initialRouteParams}
>
<HomeTabsNavigator.Screen name={'Feed'} component={'<add react component>'} />
<HomeTabsNavigator.Screen name={'Dashboard'} component={'<add react component>'} />
<HomeTabsNavigator.Screen name={'Friends'} component={'<add react component>'} />
</HomeTabsNavigator.Navigator>
);
};
const Stack = createStackNavigator();
const StackRenderer = () => {
const initialRouteName = 'FirstTabNav';
const initialRouteParams = {};
return (
<NavigationContainer>
<Stack.Navigator initialRouteName={initialRouteName}
initialRouteParams={initialRouteParams}
headerMode={'none'}
>
<Stack.Screen name={'FirstTabNav'} component={HomeTabRenderer} />
<Stack.Screen name={'SecondTabNav'} component={OtherTabRenderer} />
</Stack.Navigator>
</NavigationContainer>
)
}

Related

How to pass params from a stack navigator to a Material top tab navigator?

I have a Stack named as PaymentStack which consists of two Stack screens. The second screen consists of a MaterialTopTabs which have two other Screens named as 'Net banking' and 'Cash Payment'.
PaymentStack consists of two screens, one screen is a simple Stack screen navigator with a functional component passed in the component attribute of Stack.Screen but for the other screen I have tried to make a Material Top tabs Navigator
const TopTabStack = createMaterialTopTabNavigator();
//this MaterialTopTab is passed as a component in the below PaymentStack tab navigator
const MaterialTopTab = ({ navigation }) => (
<TopTabStack.Navigator>
<TopTabStack.Screen
name={'Net banking'}
component={ComponentX} //*I want to receive the params in this screen/cmpnt.
/>
<TopTabStack.Screen
name={'Cash payment'}
component={ComponentX}
/>
</TopTabStack.Navigator>
)
//this PaymentStack is passed as a component in Bottom tab navigator
const PaymentStack = ({navigation}) => {
<Stack.Navigator>
<Stack.Screen
name={'PaymentOption'}
component={ComponentY} //Suppose I am on this Screen
/>
<Stack.Screen
name={'MaterialTopTab'}
component={MaterialTopTab} //this component is defined above
/>
</Stack.Navigator>
}
export default function AppStack = () => {
return (
<NavigationContainer>
<PaymentStack /> //defined above
</NavigationContainer>
);
}
Now suppose I am in the screen named PaymentOption whose component is ComponentY and I want to navigate to the Screen named as Material top tab whose component is a Material top tab navigator in which two screens are present named as Net banking and Cash payment and receive the params in the Net banking. How can we do this ?
I tried
navigation.navigate('MaterialTopTab', {body : data} )
But when I am accessing the body in ComponentX , it shows undefined.
function ComponentX({route}){
console.log(route.params.body)
.......
.......
}
Ok, hopefully this is what you're looking for. Please ignore the typescript typings if you aren't using Typescript. As you can see, our RootStack component is a stack navigator that contains 1 screen and a TabNavigator. I don't have experience using top tabs but I'm pretty sure it works the same way as bottom tabs. We can navigate to our TabNavigator from the first screen in RootStack (Screen1), passing a prop called helloKitty to the TabNavigator. The TabNavigator then passes the helloKitty prop from route.params to the first screen in the TabNavigator (TabScreen1). I'm not particularly sure if what I did with TabScreen1Props is the proper way to do it, but it works for now. Honestly though, at this point, if this is what your navigation structure looks like, why not consider useContext or a state management library like Zustand?
import React, { useEffect } from 'react'
import { Text, View } from 'react-native'
import { createStackNavigator, StackScreenProps } from '#react-navigation/stack'
import { BottomTabScreenProps } from '#react-navigation/bottom-tabs'
import { Button } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
type HelloKittyType = string
type RootStackParamList = {
Screen1: undefined
SomeCuteTabs: { helloKitty: HelloKittyType }
}
type RootStackNavigationProps = StackScreenProps<RootStackParamList>
type SomeCuteTabsParamList = {
TabScreen1: undefined
TabScreen2: undefined
}
type SomeCuteTabsNavigationProps = BottomTabScreenProps<SomeCuteTabsParamList>
const RootStack = createStackNavigator<RootStackParamList>()
const SomeCuteTabs = createStackNavigator<SomeCuteTabsParamList>()
const Screen1 = ({ navigation }: RootStackNavigationProps) => (
<View>
<Button title="Go to tabs" onPress={() => navigation.navigate('SomeCuteTabs', { helloKitty: 'I love hello kitties' })} />
</View>
)
interface TabScreen1Props extends SomeCuteTabsNavigationProps {
helloKitty: HelloKittyType | undefined
}
const TabScreen1 = ({ route, navigation, helloKitty }: TabScreen1Props) => {
useEffect(() => {
console.log(helloKitty)
}, [])
return (
<View>
<Text>Tab Screen 1</Text>
</View>
)
}
const TabScreen2 = () => (
<View>
<Text>Tab Screen 1</Text>
</View>
)
const RootStackComponent = () => (
<RootStack.Navigator>
<RootStack.Screen name="Screen1" component={Screen1} />
<RootStack.Screen name="SomeCuteTabs" component={SomeCuteTabsComponent} />
</RootStack.Navigator>
)
const SomeCuteTabsComponent = ({ route, navigation }: RootStackNavigationProps) => (
<SomeCuteTabs.Navigator>
<SomeCuteTabs.Screen name="TabScreen1">{(props) => <TabScreen1 {...props} helloKitty={route.params?.helloKitty} />}</SomeCuteTabs.Screen>
<SomeCuteTabs.Screen name="TabScreen2" component={TabScreen2} />
</SomeCuteTabs.Navigator>
)
export default function App() {
return (
<NavigationContainer>
<RootStackComponent />
</NavigationContainer>
)
}

React Native Nested Stack Navigation issue

TL;DR Please excuse me, for the mess I've made here and If something is unclear
I made the following react native stack navigation
import { NavigationContainer, createNativeStackNavigator, useNavigation } from '#react-navigation/native'
import { Pressable, Text } from 'react-native'
const LoginStack = createNativeStackNavigator()
const hideHeader = { headerShown: false }
const LoginNavigation = () => {
return (
<LoginStack.Navigator initialRouteName="SignInScreen">
<LoginStack.Screen name="SignInScreen" component={SignInScreen} options={hideHeader}/>
<LoginStack.Screen name="OTPScreen" component={OTPScreen} options={hideHeader}/>
</LoginStack.Navigator>
)
}
const LoginScreen = () => (
<View>
<View>...Some Other UI code is here</View>
<LoginNavigation />
</View>
)
const ProfileScreen = () => {
const navigation = useNavigation()
return (
<View>
<Pressable onPress={() => navigation.navigate('LoginScreen')}> 👈🏻
<Text>Go to Login </Text>
</Pressable>
</View>
)
}
const RootStack = createNativeStackNavigator()
const RootNavigation = () => {
return (
<RootStack.Navigator initialRouteName="LoginScreen">
<RootStack.Screen name="LoginScreen" component={LoginScreen} options={hideHeader}/>
<RootStack.Screen name="ProfileScreen" component={ProfileScreen} options={hideHeader}/>
</RootStack.Navigator>
)
}
const App = () => {
return (
...other provders
<NavigationContainer>
<RootNavigation />
</NavigationContainer>
)
}
The navigation flow goes like this
LoginScreen -> (SignInScreen -> OTPScreen) -> ProfileScreen
The problem is that every time I dispatch "LoginScreen" navigation from "ProfileScreen," it goes to "OTPScreen" instead of "SignInScreen." Yes, that does sound strange, but after numerous tests, the result remains the same.
I'm positive the reason is the router cache, but I'm not sure how to solve it. Tried clearing cache by following few answers here but no luck
I've figured out a way to fix this and it's functioning 👇🏻
navigation.reset({index: 0, routes: [name: 'LoginScreen']})
but it is moving forward (but it must go backwards like goback)
Can someone help me with this, or is there a better way to do this?

"Error: Creating a navigator doesn't take an argument."

I am trying to create a navigation bar for my application in react native. After a day with the application running normally, I opened it and then I came across this error: "Error: Creating a navigator doesn't take an argument.". I hoped someone could help me so that I can proceed. Here is my code:
import React from "react";
import {Text, StyleSheet} from "react-native";
import {createAppContainer} from "#react-navigation/native";
import {createStackNavigator} from "#react-navigation/stack";
import Feed from "./src/screens/Feed/matrix";
const MainNavigator = createStackNavigator(
{
Feed
},
{
defaultNavigationOptions: {
headerTitle: <Text>𝓨𝓮𝓼𝓱𝓾𝓪𝓹𝓹</Text>,
}
});
export default createAppContainer(MainNavigator); '''
This error is trigger when you pass a param to the createStackNavigator() function.
With react-navigation 5, you can create the stack navigator just like that:
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
onst Stack = createStackNavigator();
const FirstScreenComponent = () => <View><Text>First screen</Text></View>
const SecondScreenComponent = () => <View><Text>Sezcond screen</Text></View>
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="First screen" component={FirstScreenComponent} />
<Stack.Screen name="Second screen" component={SecondScreenComponent} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
If you still want to use it with function (on your example), I think you should downgrade react-navigation to the v4.
Tell me if it solves your problem.

Context hook interfares with React Navigation routing

My React Native (0.61.5)/React 16.9.0 app has nested 3 layer react navigation (5.x) routing structure like below:
App.js (NavigationContainter/StackNavigator)
SplashScreen.js
AppScreen.js (TabNavigator)
EventStackScreen.js (StackNavigator)
Event.js (screen)
Chat.js (screen)
Newevent.js (screen)
Editevent.js (screen)
GroupStackScreen.js (StackNavigator)
Group.js (screen)
Newgroup.js (screen)
ContactStackScreen.js (StackNavigator)
Contact.js (screen)
Newcontact.js (screen)
*The file extension indicates that it is a single file.
The app will display 3 tabs and route to Chat screen under Event tab until context hook is added to AppScreen.js. With context added, I can see the Event tab and won't be able to open Chat screen.
Here is the code in AppScreen.js:
export default function AppScreen ({route, navigation}) {
console.log("Routes available in AppScreen : ", navigation.dangerouslyGetState().routes)
const authContext = React.createContext(null);
const stateContext = React.createContext(null);
const propsContext = React.createContext(null);
console.log("route in AppScreen : ", route.params);
const {data} = route.params;
//do something here
let authVal = {
myself,
result,
updateToken,
}
let stateVal = {
group_id,
grp_name,
role,
alias,
updateGroup,
updateGrpmember,
}
let propsVal = {
device_id,
}
return (
<propsContext.Provider value={propsVal}>
<authContext.Provider value={authVal}>
<stateContext.Provider value={stateVal}>
<BTab.Navigator>
<BTab.Screen name="Event" component={EventStackScreen} />
<BTab.Screen name="Group" component={GroupStackScreen} />
<BTab.Screen name="Contact" component={ContactStackScreen} />
</BTab.Navigator>
</stateContext.Provider>
</authContext.Provider>
</propsContext.Provider>
);
};
As soon as the 3 context providers are removed, then routing to Chat screen work again. Here is the EventStackScreen.js:
const EStack = createStackNavigator();
export default function EventStackScreen({route, navigation}) {
const data = route.params.data;
//do something....
return (
<EStack.Navigator initialRouteName="Event">
<EStack.Screen name="Event" component={Event} />
<EStack.Screen name="New Event" component={NewEvent} />
<EStack.Screen name="Edit Event" component={EditEvent} />
<EStack.Screen name="Chat" component={Chat} />
</EStack.Navigator>
);
}
I have been rubbing my head quite some time for this routing problem and haven't figured out where is the problem. The last resort is to get rid of the context and pass the variable value in a traditional way even though it is recommended by React Navigation to use context instead.
To solve the problem, move all the context related code into a GlobalContext.js and import it in AppScreen.js with import {authContext, stateContext, propsContext} from "./GlobalContext". Here is the GlobalContext.js:
import React, {Component} from 'react';
const authContext = React.createContext(null);
const propsContext = React.createContext(null);
const stateContext = React.createContext(null);
export {authContext, stateContext, propsContext}

UI Kitten: can't find variable index (BottomNavigation)

Actually i'm trying to use BottomNavigation from UI Kitty but when i'm trying to swap from one navigation tab to another the app crash with the following error:
can't find variable index
Here is the code from BottomNavigation where i use index
import React from 'react';
import { BottomNavigation, BottomNavigationTab } from 'react-native-ui-kitten';
import { createAppContainer } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import Dashboard from '../navigation/Dashboard';
import Settings from '../navigation/Settings';
export const BottomNavigationShowcase = (props) => {
const onTabSelect = (selectedIndex) => {
const { [index] : selectedRoute } = props.navigation.state.routes; // INDEX IS USED HERE
props.navigation.navigate(selectedRoute.routeName);
};
return (
<BottomNavigation
selectedIndex={props.navigation.state.index}
onSelect={onTabSelect}>
<BottomNavigationTab title='Dashboard' />
<BottomNavigationTab title='Settings' />
</BottomNavigation>
);
}
export const BottomTabNavigator = createBottomTabNavigator({
Dashboard: Dashboard,
Settings: Settings,
}, {
initialRouteName: 'Dashboard',
tabBarComponent: BottomNavigationShowcase,
});
export default createAppContainer(BottomTabNavigator)
And here is App.JS
import NavigationContainer from './components/BottomNavigation';
const App: () => React$Node = () => {
return (
<ApplicationProvider mapping={mapping} theme={lightTheme}>
<IconRegistry icons={EvaIconsPack} />
<Header/>
<NavigationContainer/>
</ApplicationProvider>
);
};
There seems to be a problem in const { [index] : selectedRoute } = props.navigation.state.routes; // INDEX IS USED HERE
which is not the right way to read an object.
It seems like you want to read the routes from the props. Why not do something like
const routes = props.navigation.state.routes;
const selectedRoute = routes[selectedIndex];
props.navigation.navigate(selectedRoute.routeName);
This should fix the app from crashing due to not finding index

Resources