React-navigation multiple stack navigator with inital route - react-native

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

Pass Flatlist value item to another Navigation Container React Native

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;

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

How can I navigate from one Stack to another Stack?

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.

How to get react native to rerender a page when redux state is changed

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)

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>