React navigation 6 ( navigate to another stack and specific screen) - react-native

I'm using react navigate V6 and I want to move between stacks , but this code is not working :
navigation.navigate("Stack Name", { screen: "screen Name" });
#react-navigation/native is not working with V6

work for me
import { createStackNavigator } from '#react-navigation/stack';
const MyStack = createStackNavigator();
const SettingsStack = createStackNavigator();
function HomeStackScreen() {
return (
<MyStack.Navigator>
<MyStack.Screen name="Home" component={HomeScreen} />
<MyStack.Screen name="Details" component={DetailsScreen} />
</MyStack.Navigator>
);
}
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Profile" component={ProfileScreen} />
</SettingsStack.Navigator>
);
}
import { useNavigation } from '#react-navigation/native';
function HomeScreen() {
const navigation = useNavigation();
const handlePress = () => {
navigation.navigate('Settings', { screen: 'Profile' });
};
return (
<Button title="Go to Profile" onPress={handlePress} />
);
}

Related

Mixing both Stack navigation and tab navigation in react native

I'm trying to mix stack navigation and tab navigation i have 14 Screens:
Search,
Home,
CartTab,
SideBar,
Details,
PriceComparison,
ShopByCategory,
ShopByStore,
CategoryPage,
CategoryFilter,
Checkout,
Login,
Register,
ForgotPassword
I want to have Search, Home, CartTab, Sidebar as bottom navigation and the other pages as stack navigation, with SearchBy pages, Details, Price Comparison not displaying the bottom tab. I'm new to react native and i have been trying diffrent solutions however 1) i'm not able to remove the bottomtab from the wanted screens and 2) using navigation.navigate is returning me errores example using navigation.navigate('Category'); i get an error The action 'NAVIGATE' with payload {"name":"Category"} was not handled by any navigator. Do you have a screen named 'Category'?
This is my code :
StackNavigator.js:
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import {
CartTab,
Details,
Home,
Notification,
PriceComparison,
Search,
SplashScreen,
ShopByCategory,
ShopByStore,
CategoryPage,
Checkout,
CategoryFilter,
Login,
Register,
ForgotPassword
} from '../screens';
import { SideBar } from './../components';
export const MainStackNavigator = () => {
const Stack = createStackNavigator();
return (
<Stack.Navigator screenOptions={{headerShown: false}} initialRouteName={'Home'}>
{/*<Stack.Screen name="SplashScreen" component={SplashScreen} /> */}
<Stack.Screen name="Login" component={Login} options={{ tabBarVisible: false }} />
<Stack.Screen name="Register" component={Register} options={{ tabBarVisible: false }} />
<Stack.Screen name="Recovery" component={ForgotPassword} options={{ tabBarVisible: false }} />
<Stack.Screen name="Home" component={Home} options={{ tabBarVisible: false }} />
<Stack.Screen name="Notification" component={Notification} />
<Stack.Screen name="Comparison" component={PriceComparison} options={{ tabBarVisible: false }} />
<Stack.Screen name="ShopByCategory" component={ShopByCategory}/>
<Stack.Screen name="ShopByStore" component={ShopByStore}/>
{/*<Stack.Screen name="Category" component={CategoryPage}/>
<Stack.Screen name="CategoryFilter" component={CategoryFilter}/>*/}
</Stack.Navigator>
);
}
export const CartStackNavigator = () => {
const Stack = createStackNavigator();
return (
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name="Cart" component={CartTab} />
<Stack.Screen name="Checkout" component={Checkout}/>
</Stack.Navigator>
);
}
export const SearchStackNavigator = () => {
const Stack = createStackNavigator();
return (
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name="Search" component={Search} />
<Stack.Screen name="Details" component={Details}/>
</Stack.Navigator>
);
}
export const SidebarStackNavigator = () => {
const Stack = createStackNavigator();
return (
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name="Sidebar" component={SideBar} />
<Stack.Screen name="ShopByCategory" component={ShopByCategory}/>
<Stack.Screen name="ShopByStore" component={ShopByStore}/>
<Stack.Screen name="Category" component={CategoryPage}/>
</Stack.Navigator>
);
}
TabNavigation.js:
import 'react-native-gesture-handler';
import React from 'react';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {COLORS} from '../constants';
import { CartStackNavigator, MainStackNavigator, SearchStackNavigator, SidebarStackNavigator }
from '../navigation/StackNavigator';
import { useStateContext } from '../context/StateContext';
const Tab = createBottomTabNavigator();
export const TabNavigation = ({navigation}) => {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
headerShown: false,
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'home'
: 'home-outline';
} else if (route.name === 'Cart') {
iconName = focused ? 'cart' : 'cart-outline';
} else if (route.name === 'Search') {
iconName = focused ? 'search' : 'search-outline';
} else if (route.name === 'SideBar') {
iconName = focused ? 'grid' : 'grid-outline';
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: COLORS.primary,
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={MainStackNavigator} />
<Tab.Screen name="Search" component={SearchStackNavigator} />
<Tab.Screen name="Cart" component={CartStackNavigator} options={{ tabBarBadge: 3, tabBarBadgeStyle: { backgroundColor: COLORS.primary, marginTop: -5 } }}/>
<Tab.Screen name="SideBar" component={SidebarStackNavigator} />
</Tab.Navigator>
);
};
App.js:
import React from "react";
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import CustomDrawer from './navigation/CustomDrawer'
import {StateContext} from './context/StateContext'
import { Home, CartTab, Search, SideBar, SplashScreen, Notification, Login, Register,
ForgotPassword } from "./screens";
import { Header, TabNavigation } from "./components";
import { StripeProvider } from '#stripe/stripe-react-native';
const Stack = createStackNavigator();
const App = () => {
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 3000);
}, []);
if (isLoading) {
return <SplashScreen />;
}
return (
<StateContext>
<NavigationContainer>
<TabNavigation/>
</NavigationContainer>
</StateContext>
);
}
export default App
Make two different Stacks file one is StackNavigation and other is BottomNavigation . Render your Stack Navigation and with calling the component of TabNavigation
I used the Dummy names of screens . Replace it according to your screen names
Stack navigation
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import {
CartTab,
Details,
Home,
} from '../screens';
import {TabNavigation } from '../navigation/StackNavigator';
export const StackNavigator = () => {
const Stack = createStackNavigator();
return (
<Stack.Navigator screenOptions={{headerShown: false}}
initialRouteName={'Home'}>
<Stack.Screen name="Home" component={TabNavigation}/>
<Stack.Screen name="ShopByCategory" component={ShopByCategory}/>
<Stack.Screen name="ShopByStore" component={ShopByStore}/>
<Stack.Screen name="CategoryFilter" component={CategoryFilter}/>
</Stack.Navigator>
);
}
Bottom Tab Navigation
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
export const TabNavigation = ({navigation}) => {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
headerShown: false}
})}>
<Tab.Screen name="Example" component={Example} />
<Tab.Screen name="Search" component={Search} />
<Tab.Screen name="SideBar" component={SideBar} />
</Tab.Navigator>
);
};

undefined is not an object react navigation from doc

I have this code that come directly from the doc of react navigation link here.
import * as React from 'react';
import { Button } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const MyStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigation.navigate('Profile', { name: 'Jane' })
}
/>
);
};
const ProfileScreen = ({ navigation, route }) => {
return <Text>This is {route.params.name}'s profile</Text>;
};
const App = () => {
return (
<NavigationContainer>
<HomeScreen />
</NavigationContainer>
);
};
export default App;
and when i click on the button i have this error : undefined is not an object. can you help me found what's wrong ?
That just to test at the end i want different page in my app and navigate into,
i don't understant why all the different page is on the same file ...
Thank you,
have good coding day
The Reason Behind this is you are used HomeScreen component inside App component.You Have to use MyStack component inside the App component.
then you get error about NavigationContainer you have to use NavigationContainer one time not in nested.Please remove NavigationContainer from App component or MyStack component.
also Add ..
import{Text} from 'react-native';
congratulations Your Programm run perfectly.
I Changed small things in your code please copy and then try it will work.
import * as React from 'react';
import { Button,Text} from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const MyStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigation.navigate('Profile', { name: 'Jane' })
}
/>
);
};
const ProfileScreen = ({ navigation, route }) => {
return <Text>This is {route.params.name}'s profile</Text>;
};
const App = () => {
return (
<MyStack />
);
};
export default App;
Happy Coding

How to join 2 stack navigators in React Native

I have 2 stack navigators that handles 2 diferrent slices of my app, one will be the authentication and the other will be the app itself. I would like to put these 2 stack navigators in different files and one file to join both. Is there a way to do this?
MainNavigation code
import React from 'react'
import {NavigationContainer} from '#react-navigation/native'
import AuthNav from './AuthNav'
import AppNav from './AppNav'
const MainNav = () => {
return (
<NavigationContainer>
<AuthNav />
<AppNav />
</NavigationContainer>
)
}
export default MainNav
AppNavigation code
const Stack = createStackNavigator<AppNavParams>()
const AppNav = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Register">
{props => <RegisterScreen {...props} />}
</Stack.Screen>
</Stack.Navigator>
)
}
AuthNavigation Code
const Stack = createStackNavigator<AppNavParams>()
const AuthNav = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Login">
{props => <RegisterScreen {...props} />}
</Stack.Screen>
</Stack.Navigator>
)
}
edit1: removed image and inserted code
You just need to verify if your authenticated token exist or not, in your MainNav
And create a stack navigator around both AppNav and AuthNav
You can do something like this
import React, { useState, useEffect, useRef } from 'react'
import { NavigationContainer, useLinking } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
import AppNav from './AppNav'
import AuthNav from './AuthNav'
const AppStack = createStackNavigator()
const MainNav() => {
const someFn = () => {
// write your logic here. Either retrieve from redux store or from local storage
// return true or false
}
const isLoggedIn = someFn()
return (
<NavigationContainer>
<AppStack.Navigator>
{isLoggedIn ? (
<AppStack.Screen name='App' component={AppNav} />
) : (
<AppStack.Screen name='Auth' component={AuthNav} />
)}
</AppStack.Navigator>
</NavigationContainer>
)
}
You need to create an auth stack and user stack and render based on sign state.
Create your auth stack.
const Stack = createStackNavigator();
export default function AuthStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
</Stack.Navigator>
);
}
Create your user stack.
const Stack = createStackNavigator();
export default function UserStack() {
return (
<Stack.Navigator>
<Stack.Screen name="User" component={UserScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
Render auth or user based on sign state.
export default function Account({ navigation, route }) {
const [sign, setSign] = useState(false);
useEffect(() => {
// some logic to check user sign
}, []);
if (sign) {
return <UserStack />;
} else {
return <AuthStack />;
}
}
Wrap with navigation container
<NavigationContainer>
<Account/>
</NavigationContainer>

Why after login my react-navigation routing does not work properly?

I have navigation container(created in react-navigation)
const AppStack = createStackNavigator();
const AppStackScreen = () => (
<AppStack.Navigator>
<AppStack.Screen name="Tabbed" component={TabsScreenNavigationScreen} />
</AppStack.Navigator>
);
class AppNavigationContainer extends Component {
constructor(props) {
super(props);
this.state = {
appLoading : true,
}
}
user = {};
componentDidMount() {
let _this = this;
this.getUser()
.then(() => {
this.setState({appLoading: !_this.state.appLoading})
})
}
getUser = async () => {
return await AsyncStoreService.getUserFromStore()
.then((user) => {
this.user = user;
});
}
render() {
const user = this.user;
const {
appLoading
} = this.state;
return (
<NavigationContainer>
{appLoading ?
<SplashScreen/>
:
<>
{user ?
<AppStackScreen/>
:
<AuthStackNavigationScreen/>
}
</>
}
</NavigationContainer>
)
}
}
export default AppNavigationContainer;
How can you see I have separated modules for app and login. login router:
const AuthStack = createStackNavigator();
const AuthStackNavigationScreen = () => (
<AuthStack.Navigator>
<AuthStack.Screen
name="ChooseRole"
component={SelectRoleScreen}
options={{title: false}}
/>
<AuthStack.Screen
name="AuthStart"
component={MainScreen}
options={{title: false}}
/>
<AuthStack.Screen
name="SignIn"
component={LoginScreen }
options={{title: 'Sign In'}}
/>
<AuthStack.Screen
name="CreateAccount"
component={RegisterScreen}
options={{title: 'Create Account'}}
/>
</AuthStack.Navigator>
);
export default AuthStackNavigationScreen;
Tabbed router for app:
const GalleryStack = createStackNavigator();
const SearchStack = createStackNavigator();
const MessagesStack = createStackNavigator();
const MenuStack = createStackNavigator();
const Tabs = createBottomTabNavigator();
const GalleryStackScreen = () => (
<GalleryStack.Navigator>
<GalleryStack.Screen name="Gallery" component={GalleryScreen} />
<GalleryStack.Screen name="GalleryItem" component={GalleryItemScreen} />
</GalleryStack.Navigator>
);
const SearchStackScreen = () => (
<SearchStack.Navigator>
<SearchStack.Screen name="Search" component={SearchScreen} />
<SearchStack.Screen name="SearchResults" component={SearchResultsScreen} />
</SearchStack.Navigator>
);
const MessagesStackScreen = () => (
<MessagesStack.Navigator>
<MessagesStack.Screen name="ConversationList" component={ConversationListScreen} />
<MessagesStack.Screen name="Conversation" component={ConversationScreen} />
</MessagesStack.Navigator>
);
const MenuStackScreen = () => (
<MenuStack.Navigator>
<MenuStack.Screen name="Menu" component={MenuScreen} />
<MenuStack.Screen name="About" component={AboutScreen} />
</MenuStack.Navigator>
);
const TabsScreenNavigationScreen = () => (
<Tabs.Navigator>
<Tabs.Screen name="Gallery" component={GalleryStackScreen} />
<Tabs.Screen name="Search" component={SearchStackScreen} />
<Tabs.Screen name="Messages" component={MessagesStackScreen} />
<Tabs.Screen name="Menu" component={MenuStackScreen} />
</Tabs.Navigator>
);
export default TabsScreenNavigationScreen;
So on login screen name="SignIn" I login, perform navigation.navigate('Tabbed') after succesfully login and get message:
The action 'NAVIGATE' with payload {"name":"Tabbed"} was not handled by any navigator.
Do you have a screen named 'Tabbed'?
He doesnt 'see' my tab navigation. Why it happens so(I have such screen name and put it to render), and how can I fix this?
According to the stack you have you will either have the appstack or the authstack at a given moment
<>
{user ?
<AppStackScreen/>
:
<AuthStackNavigationScreen/>
}
</>
So you cant navigate to tabbed from signin screen which does not exist.
The way you can handle this is update the user object maybe using a callback function or use context instead of state which will trigger a render of the AppNavigationContainer and the tabbed stack will automatically rendered instead of the auth stack. You wont need a navigate you should do the same for logout to where you will set the user to null.
You can refer more on Auth flows

How do I get a different header for each tab in React Native?

I'm working on an eBook/AudioBook app. I currently have three screens that are inside a BottomTabNavigator, with that navigator being nested within a stack navigator so I can show a header:
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import { Entypo, MaterialIcons } from "#expo/vector-icons";
import Header from "./src/components/Header";
import HomeScreen from "./src/screens/HomeScreen";
import ListenScreen from "./src/screens/ListenScreen";
import AccountScreen from "./src/screens/AccountScreen";
export const navigator = createStackNavigator(
{
mainFlow: createBottomTabNavigator(
{
Home: HomeScreen,
Listen: ListenScreen,
Account: AccountScreen,
},
),
},
{
defaultNavigationOptions: {
headerTitle: () => <Header />,
headerTitleAlign: "center",
},
}
);
HomeScreen.navigationOptions = {
tabBarIcon: <Entypo name="home" size={30} />,
};
ListenScreen.navigationOptions = {
tabBarIcon: <Entypo name="music" size={30} />,
};
AccountScreen.navigationOptions = {
tabBarIcon: <MaterialIcons name="account-circle" size={30} />,
};
const App = createAppContainer(navigator);
export default () => {
return <App />;
};
I created a custom header, but it doesn't change as go tab-to-tab. Is there a way to fix that?
In react-navigation v5, I have same problem, I wanted to have different header for each tab screen, so I solved my problem with defining each tab as a stack, then this inner stack could have self header.
const Tab = createBottomTabNavigator();
const HomeStack = createStackNavigator();
const SettingsStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="A"
component={A}
options={{ tabBarLabel: 'Home!' }}
/>
</HomeStack.Navigator>
);
}
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen
name="B"
component={B}
options={{ tabBarLabel: 'Settings!' }}
/>
</SettingsStack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
As above code, each tab.screen has inner stack as component, that has self header.
Screen options with nested navigators