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>
Related
I try to pass flatlist item value to other screen (main navigator), but it always return undefined. I want to achieve that when user onPress(), it will pass the value into the new screen, because I need it in the tab navigator screens. I already try to pass using using routes, but it also return undefined.
App.js
import React, {Component} from 'react';
import 'react-native-gesture-handler';
import {createStackNavigator} from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
//import another Page
import AccountSelectScreen from './screens/AccountSelectScreen';
import NewAccountScreen from './screens/NewAccountScreen';
import MainNavigator from './screens/MainNavigator';
import HomeScreen from './screens/HomeScreen';
import VaccineScreen from './screens/VaccineScreen';
import NotificationScreen from './screens/NotificationScreen';
import UserScreen from './screens/UserScreen';
import SplashScreen from './screens/SplashScreen';
import SignUpAccScreen from './screens/SignUpAccScreen';
import RegisterScreen from './screens/RegisterScreen';
import ScanQR from './screens/ScanQR';
const styles = require('./styles/styles');
const Stack = createStackNavigator();
const Auth = (route) => {
// Stack Navigator for Login and Sign up Screen
return (
<Stack.Navigator initialRouteName="SignUpAcc">
<Stack.Screen
name="SignUpAcc"
component={SignUpAccScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="AccountSelectScreen"
component={AccountSelectScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="NewAccountScreen"
component={NewAccountScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="RegisterScreen"
component={RegisterScreen}
options={{headerShown: false}}
/>
</Stack.Navigator>
);
};
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="SplashScreen">
<Stack.Screen
name="SplashScreen"
component={SplashScreen}
// Hiding header for Splash Screen
options={{headerShown: false}}
/>
{/* Auth Navigator: Include Login and Signup */}
<Stack.Screen
name="Auth"
component={Auth}
options={{headerShown: false}}
/>
{/* Navigation Drawer as a landing page */}
<Stack.Screen
name="MainNavigator"
component={MainNavigator}
// Hiding header for Navigation Menu
options={{headerShown: false}}
/>
<Stack.Screen
name="BarcodeScan"
component={ScanQR}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
renderItem flatlist
const renderItem = ({ item }) => (
<View style={{marginBottom: 20}}>
<Pressable
style={styles.baby_box}
title={item.nameVal}
>
<Text>{item.nameVal}</Text>
</Pressable>
<Pressable
style={styles.btnDelete}
value={item.nameVal}
onPress={() => {
// selectChild(text)
navigation.navigate('MainNavigator',{
nameChild: item.nameVal
});
}}
>
<Text style={styles.btnText}>Pilih</Text>
</Pressable>
</View>
);
const MainNavigator = (route,navigation) => {
const {nameChild} = route.params;
}
export default MainNavigator;
From this given code i think you are destructuring props in the wrong way thats why its undefined.
const MainNavigator = (route,navigation) => {
const {nameChild} = route.params;
}
export default MainNavigator;
Try this.
const MainNavigator = (props) => {
const {nameChild} = props.route.params;
}
export default MainNavigator;
You have to add curly braces so it takes parameters with in the object
Like this:({route,navigation})
const MainNavigator = ({route,navigation}) => {
const {nameChild} = route.params;
}
export default MainNavigator;
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 />;
}
I am using the latest version of React native. I need to navigate from one Stack .Navigator to another Stack.Navigator.
The structure would be the following:
-Stack.Navigator (LoginStack)
-Stack Screen -> LoginScreen
-Stack.Screen -> CreateAccount
-Stack.Navigator (ProdsStack)
-Stack.Screen -> ProdsScreen
-Stack.Screen -> DetailsScreen
I need to navigate from LoginScreen to ProdsScreen, I've tried Navigation.navigate but it doesn't give me any results.
This is the code for my router:
import React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import LoginStack from './src/components/Login/LoginStack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import ListProdsStack from './src/components/ListProds/ListProdsStack';
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
function MainTabScreen() {
return (
<Tab.Navigator>
<Tab.Screen name="ProdListTab" component={ListProdsStack} />
</Tab.Navigator>
);
}
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="LoginStack"
component={LoginStack}
options={{headerShown: false}}
/>
<Stack.Screen
name="ProdListStack"
component={MainTabScreen}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
This is my LoginStack
const Stack = createStackNavigator();
const LoginStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#F2F302',
},
headerTintColor: '#3C2B58',
}}>
<Stack.Screen
name="Login Screen"
component={LoginScreen}
options={{headerShown: false}}
/>
<Stack.Screen name="Cuenta Nueva" component={CreateAccount} />
</Stack.Navigator>
);
};
This is my ListProfsStack:
const Stack = createStackNavigator();
const ListProdsStack = () => {
return (
<Stack.Navigator>
<Stack.Screen name="ProdList" component={ListProdsScreen} />
</Stack.Navigator>
);
};
I was thinking of using different Stacks because each Tab has its own screens which cannot be accessed from one Stack to another Stack directly.
I am using using redux state to render screens for authentication. I use the user token save using AsyncStorage to ditermine whether the user is logged in or not and then I set the redux state to true or false.
Here is my App.js
// Importing dependencies
import React, { Component, useEffect, useState } from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
import {store } from "./components/apiCall"
import * as font from "expo-font";
export default function App() {
AsyncStorage.getItem("auth").then((val) =>
updateAuth(val)
);
function updateAuth(value) {
value == "true" ? store.dispatch({ type: "Login" }) : store.dispatch({ type: "Signout" });
}
return store.getState().isLoggedIn ? (
<NavigationContainer>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Chat" component={Chat} />
<Stack.Screen name="SearchResult" component={SearchResult} />
<Stack.Screen name="ContactDetails" component={contactDetails} />
</Stack.Navigator>
</NavigationContainer>
) : (
<NavigationContainer>
<Stack.Navigator headerMode="none">
<Stack.Screen name="Welcome" component={Welcome} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Signup" component={Signup} />
</NavigationContainer>
);
}
I am use the state to ditermine what screens to render. When the user presses signout in my app I set the state to false but the screens that are being rendered do not change the state unless I reload the App
The problem is that you are getting isLoggedIn from store.getState(). And react actually treating this as a static value, so it not watching for changes and does not trigger rerenders.
You should get is isLoggedIn from useSelector hook:
const { isLoggedIn } = useSelector()
option 2:
const isLoggedIn = useSelector(state => state.isLoggedIn)
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>