How to join 2 stack navigators in React Native - 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>

Related

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

Drawer Navigation react native paper

I am extremely new to React and React Native. I need some help regarding nesting a drawer navigator inside the current Stack Navigation.
I have the code on Snack, If someone can please help me i will really appreciate.
https://snack.expo.dev/#smith.james1982/github.com-callstack-react-native-paper-login-template
I want to put the Drawer navigation with Hamburger and Back Arrow using react-native-paper on the Home Screen.
Thanks very much in advance..
This is how i achieved the solution basically 2 navigations and using a state sharing library use-between. Hopefully it can be helpful to someone
import React, { memo, useState } from "react";
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { NavigationContainer } from "#react-navigation/native";
import { HomeScreen, LoginScreen, RegisterScreen, ForgotPasswordScreen, Dashboard, Demo } from "./screens";
import { useLoginState } from "./core/state";
import { useBetween } from "use-between";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
//Login navigation
const LoginNav = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="HomeScreen"
>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen name="RegisterScreen" component={RegisterScreen} />
<Stack.Screen name="ForgotPasswordScreen" component={ForgotPasswordScreen} />
<Stack.Screen name="Dashboard" component={Dashboard} />
</Stack.Navigator>
</NavigationContainer>
);
};
//Logged in Navigation
const LoggedInNav = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={Demo} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default function App() {
const { loggedIn, setIsLoggedIn } = useBetween(useLoginState);
return loggedIn ? <LoggedInNav /> : <LoginNav />;
}

React-navigation multiple stack navigator with inital route

So i was creating RN project which had multiple stack navigator
Logged In Routes
Non Logged in routes
So I have non logged in routes like this
import React from "react"
import { createNativeStackNavigator } from "react-native-screens/native-stack"
import { Introduction, Login } from "#src/screens/loggedOut"
const Stack = createNativeStackNavigator()
const defaultOptions = {
headerShown: false
}
const LoggedOutRoutes = () => {
return (
<Stack.Navigator initialRouteName="introduction">
<Stack.Screen name="introduction" component={Introduction} options={defaultOptions} />
<Stack.Screen name="login" component={Login} options={defaultOptions} />
</Stack.Navigator>
)
}
export default LoggedOutRoutes
And similarly logged in routes
import React from "react"
import { createNativeStackNavigator } from "react-native-screens/native-stack"
import {Home,Settings } from "#src/screens/loggedIn"
const Stack = createNativeStackNavigator()
const defaultOptions = {
headerShown: false
}
const LoggedIn = () => {
return (
<Stack.Navigator initialRouteName="home">
<Stack.Screen name="home" component={Home} options={defaultOptions} />
<Stack.Screen name="settings" component={Settings} options={defaultOptions} />
</Stack.Navigator>
)
}
export default LoggedIn
Now, I want to load either of these roots based on if user is logged in or not.
How would I do it?
Assuming you have a login state saved, you can wrap your navigation in the NavigationContainer component from "#react-navigation/native" and render the correct navigation conditionally. Something like this:
<NavigationContainer>
{userLoggedIn ? <LoggedIn /> : <LoggedOutRoutes />}
</NavigationContainer>

element type is invalid expected a string or a class/function but got object

routes.js
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import SignIn from '~/pages/SignIn';
import SignUp from '~/pages/SignUp';
import Dashboard from '~/pages/Dashboard';
const Stack = createStackNavigator();
export default (isSigned = false) => (
<NavigationContainer>
<Stack.Navigator>
{isSigned ? (
<>
<Stack.Screen name="SignIn" component={SignIn} />
<Stack.Screen name="SignUp" component={SignUp} />
</>
) : (
<Stack.Screen name="Dashboard" component={Dashboard} />
)}
</Stack.Navigator>
</NavigationContainer>
);
App.js
import { useSelector } from 'react-redux';
import createRouter from './routes';
export default function App() {
const isSigned = useSelector((state) => state.auth.signed);
const Routes = createRouter(isSigned);
return <Routes />;
}
I use react navigation v5, I am still a beginner and I was studying its new version. However, I can't define the reason for this error. The error returns that it expects a function or class, but is this not a function?
Error image
Change routes.js like this:
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import SignIn from '~/pages/SignIn';
import SignUp from '~/pages/SignUp';
import Dashboard from '~/pages/Dashboard';
const Stack = createStackNavigator();
export default ({ isSigned }) => (
<NavigationContainer>
<Stack.Navigator>
{isSigned ? (
<>
<Stack.Screen name="SignIn" component={SignIn} />
<Stack.Screen name="SignUp" component={SignUp} />
</>
) : (
<Stack.Screen name="Dashboard" component={Dashboard} />
)}
</Stack.Navigator>
</NavigationContainer>
);
Change App.js like this :
import { useSelector } from 'react-redux';
import Routes from './routes';
export default function App() {
const isSigned = useSelector((state) => state.auth.signed);
return <Routes isSigned={isSigned} />;
}

Open the drawer when I click the icon react navigation version 5

I want to open the drawer when I click the icon in the headerLeft part, I also have try to this.props.navigation.dispatch but is gives an error also navigation.dispatch gives error
The code below does not gives errors but is does not open the drawer
import { DrawerActions } from '#react-navigation/native';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createStackNavigator } from '#react-navigation/stack';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
export default class App extends Component {
createHomeStack = () =>
<Stack.Navigator>
<Stack.Screen
initialRouteName="login"
headerMode="screen"
name="main"
children={ this.createBottomTabs}
options={{
title: "Fitbit",
headerLeft: () => (
<Icon
name="menu"
size={25}
color="#D4AF37"
onPress={() => {DrawerActions.openDrawer() }}
/>
)} } />
</Stack.Navigator>
createDrawer = ({navigation}) =>
<Drawer.Navigator initialRouteName="Main" >
<Drawer.Screen name="Main" component={Main} />
<Drawer.Screen name="Contacts" component={Food} />>
</Drawer.Navigator>
render() {
return (
<NavigationContainer>
{this.createHomeStack()}
</NavigationContainer>
);
}
}
In order to achieve that you need to wrap the stack into the drawer as the documentation says.
Documentation here
I would probably use something like this:
EDIT:
Added full code
import React,{Component} from 'react'
import { NavigationContainer } from '#react-navigation/native'
import { createDrawerNavigator } from '#react-navigation/drawer'
import { createStackNavigator } from '#react-navigation/stack'
import { View } from 'react-native'
import Icon from 'react-native-vector-icons/dist/Feather'
const Drawer = createDrawerNavigator()
const Stack = createStackNavigator()
const Main = () => <View></View>
const Food = () => <View></View>
const Home = ({ navigation }) => (
<Stack.Navigator>
<Stack.Screen name="Main" component={Main} options={{
headerLeft: () => <Icon
name="menu"
size={25}
color="#D4AF37"
onPress={() => navigation.openDrawer()}
/>
}} />
</Stack.Navigator>
)
const DrawerNavigator = () => (
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Contacts" component={Food} />
</Drawer.Navigator>
)
export default props => (
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
)
You need To import DrawerActions
import {DrawerActions } from '#react-navigation/native';
And You Can Open Using
navigation.dispatch(DrawerActions.openDrawer());