React Navigation - Reset Screen on Tab Touch if screen is opened - react-native

I'm building a React Native app with React Navigation. I'm using Drawer Screens.
I need that if a Screen is opened, and I touch in its NavigatorButton, the screen will reset or at least recive an event.
NOTE: I'm not trying the screen reset when I touch to another, I need that if the screen is opened, reset it touching in his navigator tab
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import GameScreen from "./screens/GameScreen";
import { createDrawerNavigator } from "#react-navigation/drawer";
export default function App(params: { navigation: any }) {
const Drawer = createDrawerNavigator();
return (
<NavigationContainer>
<Drawer.Navigator useLegacyImplementation initialRouteName="Home">
<Drawer.Screen
name="Home"
options={{
title: "HomePage",
unmountOnBlur: true,
}}
component={GameScreen}
listeners={{
drawerItemPress: (e) => {},
}}
/>
<Drawer.Screen name="Nuevo juego" component={GameScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
}

SOLUTION
Well, I found a way to get "navigation" inside NavigationContainer. I hope it helps someone
import React from 'react'
import { NavigationContainer } from '#react-navigation/native'
import GameScreen from './screens/GameScreen'
import {
createDrawerNavigator,
DrawerContent,
DrawerContentScrollView,
DrawerItem,
DrawerItemList,
} from '#react-navigation/drawer'
export default function App(params: { navigation: any }) {
const Drawer = createDrawerNavigator()
const CustomDrawers = (props: any) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
label={'Nuevo juego'}
onPress={() =>
props.navigation.reset({
index: 0,
routes: [{ name: 'Home' }],
})
}
/>
</DrawerContentScrollView>
)
}
return (
<NavigationContainer>
<Drawer.Navigator
useLegacyImplementation
initialRouteName="Home"
drawerContent={(props) => CustomDrawers(props)}>
<Drawer.Screen
name="Home"
options={{
title: 'Continuar',
// unmountOnBlur: true,
}}
component={GameScreen}
/>
</Drawer.Navigator>
</NavigationContainer>
)
}

Related

react native navigation.navigate is not working in nested navigator

//Here is my App.js file
import React, {Suspense} from 'react';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
} from 'react-native';
import {
NavigationContainer,
getFocusedRouteNameFromRoute,
} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import DrawerNavigator from './navigation/DrawerNavigator';
const SinginScreens = React.lazy(() => import('./screens/Login/SinginScreens'));
const Billing = React.lazy(() => import('./screens/Home/Billing'));
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Loading = () => {
return <SafeAreaView>{/* <Text>Loading</Text> */}</SafeAreaView>;
};
const Routes = ({navigation}) => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={'Main'}>
<Stack.Screen
name={'Main'}
component={DrawerNavigator}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="Billing"
component={Billing}
options={{
headerLeft: null,
headerShown: false,
}}
/>
<Stack.Screen
name="SinginScreen"
component={SinginScreens}
options={{
headerShown: false,
gestureEnabled: false,
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
class App extends React.PureComponent {
render() {
return (
<Suspense fallback={<Loading />}>
<Routes />
</Suspense>
);
}
}
export default App;
//Here is my stack navigator
import React from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import {Button} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
const Dashboard = React.lazy(() => import('../screens/Home/Dashboard.js'));
const Splash = React.lazy(() => import('../screens/Login/Splash'));
import {AuthContext} from './context';
const Stack = createStackNavigator();
const StackNavigator = ({route, navigation}) => {
return (
// <NavigationContainer>
<Stack.Navigator initialRouteName="Splash">
<Stack.Screen
name="Splash"
component={Splash}
options={{headerShown: false, gestureEnabled: false}}
/>
<Stack.Screen
name="Dashboard"
component={Dashboard}
options={{headerShown: false,}}
/>
</Stack.Navigator>
);
};
export default StackNavigator;
//Here is my drawer navigator
import React, {useState,useEffect} from 'react';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '#react-navigation/drawer';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import {DrawerActions} from '#react-navigation/native';
import StackNavigator from './StackNavigator';
import { useNavigation } from '#react-navigation/native';
const Drawer = createDrawerNavigator()
const CustomDrawer = props => {
return (
<View style={{flex: 1}}>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
{...props}
label="Contacts"
labelStyle={styles.itemStyle}
icon={(focused, size, color) => (
<Image
style={{width: 25, height: 25}}
source={require('../assets/images/ic_contacts1.png')}
resizeMode="contain"
/>
)}
onPress={() => {
props.navigation.closeDrawer();
}}
/>
<DrawerItem
{...props}
label="POS Catalog"
labelStyle={styles.itemStyle}
icon={(focused, size, color) => (
<Image
style={{width: 25, height: 25}}
source={require('../assets/images/catalog.png')}
resizeMode="contain"
/>
)}
onPress={() => {
props.navigation.closeDrawer();
}}
/>
</DrawerContentScrollView>
</View>
);
};
const DrawerNavigator = () => {
return (
<Drawer.Navigator
drawerContent={props => <CustomDrawer {...props} />}
screenOptions={{
drawerPosition: 'right',
// drawerType:"permanent",
headerTintColor: '#000000',
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}>
<Drawer.Screen
name="Home"
component={StackNavigator}
options={{
drawerIcon: ({focused, size}) => (
<Ionicons name="ios-home-outline" size={size} color={'#000'} />
),
headerStyle: {
backgroundColor: 'white',
},
headerShown: false,
headerTintColor: 'black',
}}/>
</Drawer.Navigator>
);
};
export default DrawerNavigator;
I have drawer and stack navigator in my react native application.I have Screens called Splash,SigninScreen,Billing and Dashboard.
Screens in navigator
Splash,Dashboard- Stack Navigator
SigninScreen,Billing-App.js file(mentioned these screens out of drawer navigator to remove drawer for these screens)
What i want to achieve is when app is opening splash screen comes first and from splashscreen i am navigating to signinscreen using navigation.replace('SinginScreen') to avaoid back navigating to splash screen again when user clicks back button in 'SigninScreen'.
Similarly i am using navigation.replace('Billing') when navigating from SigninScreen to Billing to avoid back navigating to SigninScreen again when user clicks back button in Billing.
Now Inside Billing i am using navigation.navigate('Dashboard') to navigate from Billing to Dashboard page.Here i am facing error like The action 'NAVIGATE' with payload {"name":"Dashboard"} was not handled by any navigator.
Do you have a screen named 'Dashboard'?
Note:
I want to navigate to Dashboard page from Billing and also i don't want the user to go back again billing from Dashboard.

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

error while updating property 'title' of a view managed by: RNScreenStackHeaderConfig (react native)

My app has a home screen (HomeScreen.js) with a bottom tab navigator, and it is nested within a stack navigator in App.js. Whenever I try and navigate to the profile screen from the home screen I get the following error:
This error only occurs when I try and set headerTitle to a custom component in App.js. Does anyone know how I can set the header of ProfileScreen to a custom component correctly?
My navigation structure looks like this:
Stack.Navigator
Tab.Navigator
Food (screen)
Friends (screen)
Lists (screen)
Profile (screen)
I am able to set a custom component as the header in Tab.Navigator, but not in Profile
Let me know if more information is needed.
App.js:
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createNativeStackNavigator } from "react-native-screens/native-stack";
import HomeArea from "./screens/HomeScreen";
import ProfileScreen from "./screens/ProfileScreen";
import NavBar from "./componets/NavBar";
import BackSVG from "./assets/BackSVG";
import { Text, View } from "react-native";
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="HomeArea"
component={HomeArea}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ProfileScreen"
component={ProfileScreen}
options={{
headerTitle: props => {
return <Text>Test</Text>;
}
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
HomeScreen.js:
import * as React from "react";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import FoodScreen from "../screens/FoodScreen";
import FriendsScreen from "../screens/FriendsScreen";
import Lunchlists from "../screens/Lunchlists";
import { StyleSheet, View } from "react-native";
import FoodSVG from "../assets/FoodSVG";
import ListSVG from "../assets/ListSVG";
import FriendsSVG from "../assets/FriendsSVG";
import NavBar from "../componets/NavBar";
import UserSVG from "../assets/UserSVG";
const Tab = createBottomTabNavigator();
export default function HomeScreen({ navigation }) {
return (
<Tab.Navigator
screenOptions={{
tabBarStyle: styles.navBar,
tabBarActiveTintColor: "#fff",
tabBarShowLabel: false,
header: () => (
<NavBar
symbolRight={UserSVG}
symbolLeft={View}
rightPressEvent={() => navigation.navigate("ProfileScreen")}
/>
)
}}>
<Tab.Screen
name="Food"
component={FoodScreen}
options={{
tabBarLabel: "Food",
tabBarIcon: ({ color, size }) => {
return <FoodSVG width={size} height={size} color={color} />;
}
}}
/>
<Tab.Screen
name="Friends"
component={FriendsScreen}
options={{
tabBarLabel: "Friends",
tabBarIcon: ({ color, size }) => {
return <FriendsSVG width={size} height={size} color={color} />;
}
}}
/>
<Tab.Screen
name="Lunchlists"
component={Lunchlists}
options={{
tabBarLabel: "Lunchlists",
tabBarIcon: ({ color, size }) => {
return <ListSVG width={size} height={size} color={color} />;
}
}}
/>
</Tab.Navigator>
);
}
const styles = StyleSheet.create({
navBar: {
backgroundColor: "#5A4664"
}
});
I imported createNativeStackNavigator from the wrong package. In App.js I instead imported it using import { createNativeStackNavigator } from "#react-navigation/native-stack";, which solved my problems.

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 to use navigation.navigate from a component outside the stack.navigation

I have an application using React native where I am using react-navigation (5.2.9).
I built a Stack.Navigator where I've got my screens but I want the Footer component to be outside so it renders in all screens. The problem is, I can't navigate from the footer, which is what I need to do as the footer has a few buttons that should be changing the screen:
const Stack = createStackNavigator();
const App = () => {
return (
<Provider store={store}>
<NavigationContainer>
<Header />
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerShown: false
}}
/>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{
headerShown: false
}}
/>
</Stack.Navigator>
<Footer />
</NavigationContainer>
</Provider>
);
};
How do I pass the navigation prop to the footer component?
Try this:
Create a new file named: RootNavigation.js
// RootNavigation.js
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
// file where you have the navigation
import {navigationRef} from './path/to/RootNavigation';
<NavigationContainer ref={navigationRef}>
.....
<Footer />
</NavigationContainer>
And Footer.js should be something like this:
// Footer.js
import React from 'react';
import {View, Button} from 'react-native';
import * as RootNavigation from './path/to/RootNavigation';
const Footer= () => {
return (
<View>
<Button
title={'Go to'}
onPress={() =>
RootNavigation.navigate('screenName ', {userName: 'Lucy'})
}
/>
</View>
);
};
export default Footer;
For more info you can read the documentation. https://reactnavigation.org/docs/navigating-without-navigation-prop/
The components outside of the Stack.Screen components do not receive the navigation prop. So in this case, you have to get the NavigationContainer using refs in your footer component, as follows:
Create a ref with const myRef = React.createRef()
pass it to the <NavigationContainer ref={myRef}>, and
use that ref to navigate, myRef.current?.navigate(name, params).
It is all explained here. The docs here separate the creation of the ref in a new file, to allow you to import the ref without dependency loops/ issues. As the docs state, you can now call RootNavigation.navigate('ChatScreen', { userName: 'Lucy' }); in any js module, not just in a react component.
In your case though, you don't need the ref in separate file.
const Stack = createStackNavigator();
const navigationRef = React.createRef();
const App = () => {
return (
<Provider store={store}>
<NavigationContainer ref={navigationRef}>
<Header />
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerShown: false
}}
/>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{
headerShown: false
}}
/>
</Stack.Navigator>
<Footer navigationRef={navigationRef}/>
</NavigationContainer>
</Provider>
);
};
And in <Footer/> use navigationRef.current?.navigate(name, params)
From the documentation.
https://reactnavigation.org/docs/connecting-navigation-prop/
import * as React from 'react';
import { Button } from 'react-native';
import { useNavigation } from '#react-navigation/native';
function GoToButton({ screenName }) {
const navigation = useNavigation();
return (
<Button
title={`Go to ${screenName}`}
onPress={() => navigation.navigate(screenName)}
/>
);
}
I ended up building a component called screen that will just wrap the content of screen and render the header/footer based on props:
import React from 'react';
import { View } from 'native-base';
import style from './style';
import Footer from '../../footer';
import Header from '../../header';
const Screen = ({
footer,
header,
children,
navigation
}) => (
<View style={style.screen}>
{ header && <Header navigation={navigation} />}
{ children }
{ footer && <Footer navigation={navigation} />}
</View>
);
export default Screen;
And wrapping the screens of my apps like this:
<Screen header footer navigation={navigation}>
... screen content
</Screen>
I feel like it is the best way if I can't sort that problem out.
A simple trick to extract navigation out of screenOptions.
function NavWrapper() {
const navigatorRef = useRef<any>();
<Tab.Navigator
screenOptions={({ navigation: nav }) => navigatorRef.current = nav}
>
<Tab.Screen name="screen1" />
</Tab.Navigator>
}
I solve this problem with a global state using React context API:
// When enter in the HomeScreen:
const { setGlobalNavigation, globalNavigation } = useGlobalContext();
const navigation = useNavigation<RemindersNavigationProp>();
useEffect(() => {
if (setGlobalNavigation && !globalNavigation) setGlobalNavigation(navigation);
}, [setGlobalNavigation, globalNavigation, navigation]);
// When want to use:
const { globalNavigation } = useGlobalContext();
const handleNavigate = () =>
globalNavigation.navigate("contactsStack", { screen: "newContact" });