Navigation back click event in React Native - react-native

I am working on a React Native application. I am using navigation in my application. I want to do something when user presses back navigation i.e. moved to a back screen.
How can i get the click event of "blacked circle Frage" in the above image. I am working on IOS

Use a custom header with
import { Header } from "native-base";
And add below code in your route file to disable default header.
navigationOptions: {
header: null
}
my custome header code for your reference
<Header style={styles.header}>
<View style={{ flex: 2 }}>
<TouchableOpacity
style={styles.iconButton}
onPress={() => { this.createNote(); this.props.navigation.navigate('Home') }}>
<Icon name="arrow-back" size={28} color="#606060" />
</TouchableOpacity>
</View>
<View style={{ flex: 8 }}></View>
<View style={{ flex: 2 }}>
<TouchableOpacity
style={styles.iconButton}
onPress={() => { this.createNote(); this.props.navigation.navigate('Home') }}>
<Icon name="check" size={28} color="#606060" />
</TouchableOpacity>
</View>
</Header>
reference link:- https://www.npmjs.com/package/native-base

It probably varies depending on the libraries you are using. I am using react-native-paper in Expo, which uses the headerLeft option in the Stack.Screen component. Here's a complete example - save it and then 'expo start'
import { Provider as PaperProvider, Text } from 'react-native-paper'
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<PaperProvider>
<NavigationContainer >
<Stack.Navigator>
<Stack.Screen
name="Example"
options={{
title: 'Example',
headerLeft: () => <Text>Custom left button</Text>,
}}
component={() => <Text>Example body text</Text>}
/>
</Stack.Navigator>
</NavigationContainer>
</PaperProvider>
)
}

You can use onPress={() => this.props.navigation.goBack()} on TouchableOpacity if you are redirecting to the previous page
Also you can use this.props.navigation.navigate('Any_Screen') to move to other screens.
Also, I would like to suggest you to get familiar with BackHandler to move back to previous page when hardware back button is pressed.

add the code
onClick={this.props.navigation.goBack()}
or use specif navigation replace go back to
onClick={this.props.navigation.navigate('namepagespacific')}

check this screen there are mutiple example of handling click event
import React from 'react';
import { View, Text, StyleSheet, Button} from 'react-native';
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation, navigationOptions, screenProps }) => {
return {
title: navigation.getParam('title', 'A Nested Details Screen'),
};
};
render() {
const { navigation } = this.props;
const itemId = navigation.getParam('itemId', 'NO-ID');
const otherParam = navigation.getParam('otherParam', 'some default value');
return (
<View style={styles.detailsScreen}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.push('Details')}
/>
<Button
title="Go to Home"
onPress={() => this.props.navigation.navigate('Home')}
/>
<Button
title="Go back"
onPress={() => this.props.navigation.popToTop()}
/>
<Button
title="Update the title"
onPress={() => this.props.navigation.setParams({ title: 'Updated!' })}
/>
<Button
title="Modal"
onPress={() => this.props.navigation.navigate('MyModal')}
/>
</View>
);
}
}
const styles = StyleSheet.create({
detailsScreen: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
})
export default DetailsScreen;
things you have asked in the comment section I could not find any exact answer for your question but you can take a look into this url how header buttons work
https://snack.expo.io/#react-navigation/simple-header-button-v3
hope this will work for you
header: ({ goBack }) => ({
left: ( <Icon name={'chevron-left'} onPress={ () => { goBack() } } /> ),
}),
you can also follow this page https://github.com/react-navigation/react-navigation/issues/779

Related

React Native — React-Navigation back button on wrong side of appbar?

Okay so I'm just jumping into React Native and I'm going through the docs with the react-navigation package. Whenever a screen is pushed onto the stack, the animation goes from right-left by default—Also I'm noticing the back button is on the right side of the appbar instead of the left be default. Is this by design or have I set something up incorrectly?
Also ignore the FC I'm using, I know it's not recommended but I'm just getting a feel for RN 😅
See image and code below:
import { StatusBar } from "expo-status-bar";
import { Button, StyleSheet, Text, View } from "react-native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { BaseNavigationContainer } from "#react-navigation/native";
import { FC } from "react";
import { StackScreenProps } from "./Types";
const Home: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Hello World </Text>
<Button
title="Switch Page"
onPress={() => {
navigation.navigate("About");
}}
/>
</View>
);
};
const About: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Learn the Process First</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
};
const Stack = createNativeStackNavigator();
export default function App() {
return (
<BaseNavigationContainer>
{/* #ts-ignore */}
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="About" component={About} />
</Stack.Navigator>
</BaseNavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});

Having two tab navigation bars in React Navigation

I want to create an app, that has both a fixed bottom and top tab navigation bar.
See image:
After I finished the bottom navigation bar I tried the following in my App.js file:
return(
<NavigationContainer>
<Tab.Navigator> //top navbar
<Tab.Screen />
...
</Tab.Navigator>
<Tab.Navigator> //bottom navbar
<Tab.Screen />
...
</Tab.Navigator>
</NavigationContainer>
)
However, I get the error, that another navigator is already registered in this container and that I should not have multiple navigators under a single NavigationContainer.
I found multiple guides about nesting tab and stack navigators, but how do I nest multiple tab navigators, that both update the central screen?
AFAIK that is not possible without writing a custom navigator. Navigators need to be nested and need to have separate routes, so one tab navigator would need to be nested inside (as a tab of) the other.
Writing a custom navigator is something you definitely could consider. Here is a snack that modifies the example from react-navigation documentation:
https://snack.expo.io/#mlisik/thoughtful-stroopwafels
In the snack, the first two tabs are displayed on top, and remaining on the bottom. You would need to further modify them to match the appearance you are after with some custom options, perhaps reusing internal components from react-navigation.
It is by no means a complete solution, but should give you an idea of what is possible.
For completeness, I include the code here:
// App.js
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNavigator } from './Navigator';
const Nav = createNavigator()
const Screen1 = () => <View style={{flex: 1, backgroundColor: 'red'}} />
const Screen2 = () => <View style={{flex: 1, backgroundColor: 'green'}} />
const Screen3 = () => <View style={{flex: 1, backgroundColor: 'yellow'}} />
const Screen4 = () => <View style={{flex: 1, backgroundColor: 'brown'}} />
export default function App() {
return (
<NavigationContainer>
<Nav.Navigator>
<Nav.Screen name="Tab 1" component={Screen1} />
<Nav.Screen name="Tab 2" component={Screen2} />
<Nav.Screen name="Tab 3" component={Screen3} />
<Nav.Screen name="Tab 4" component={Screen4} />
</Nav.Navigator>
</NavigationContainer>
)
}
// Navigator.js
// this is only slightly modified from https://reactnavigation.org/docs/custom-navigators#usenavigationbuilder
import * as React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import {
NavigationHelpersContext,
useNavigationBuilder,
createNavigatorFactory,
TabRouter,
TabActions,
} from '#react-navigation/native';
function TabButton({ route, descriptors, navigation, state }) {
return (
<TouchableOpacity
key={route.key}
onPress={() => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!event.defaultPrevented) {
navigation.dispatch({
...TabActions.jumpTo(route.name),
target: state.key,
});
}
}}
style={{ flex: 1 }}
>
<Text>{descriptors[route.key].options.title || route.name}</Text>
</TouchableOpacity>
)
}
function Navigator({
initialRouteName,
children,
screenOptions,
tabBarStyle,
contentStyle,
}) {
const { state, navigation, descriptors } = useNavigationBuilder(TabRouter, {
children,
screenOptions,
initialRouteName,
});
const renderTab = (route) => (
<TabButton
route={route}
descriptors={descriptors}
state={state}
navigation={navigation}
/>
)
return (
<NavigationHelpersContext.Provider value={navigation}>
<View style={[{ flexDirection: 'row' }, tabBarStyle]}>
{state.routes.slice(0, 2).map(renderTab)}
</View>
<View style={[{ flex: 1 }, contentStyle]}>
{descriptors[state.routes[state.index].key].render()}
</View>
<View style={[{ flexDirection: 'row' }, tabBarStyle]}>
{state.routes.slice(2).map(renderTab)}
</View>
</NavigationHelpersContext.Provider>
);
}
export const createNavigator = createNavigatorFactory(Navigator);

Navigate to other StackNavigator screen when press button on navbar

I'm pretty new to react and this is my first app.
I have a stack navigator with 2 screens by now: MainMenu and Profile. While the user is in MainMenu, a button on top right corner is shown and I need to redirect the user to the Profile screen when this button is pressed. I need something like this.props.navigation.navigate('Profile') but this does not work, because this, props and navigation are not defined.
My thinks are that I cannot redirect to Profile from this stack navbar, cause Profile is still defined yet, but I don't know another way to do it.
// mainStack.js
import React from 'react';
import { View, Text, TouchableOpacity, Image } from 'react-native';
import { createStackNavigator } from '#react-navigation/stack';
import MainMenu from '../../screens/home/mainMenu';
import Profile from '../../containers/profileContainer';
import Icon from 'react-native-vector-icons/FontAwesome';
import { useSelector } from 'react-redux';
const MainStack = () => {
const Stack = createStackNavigator();
const isAdmin = (useSelector(state => state.auth.user.role) === 'admin');
function renderUserMenu() {
return (
<TouchableOpacity style={{ marginRight: 20 }} onPress={() => console.log("HERE I NEED TO REDIRECT TO THE SCREEN PROFILE") } >
<Icon style={{ color: 'white' }} name='user-circle-o' size={30} />
</TouchableOpacity>
)
}
function LogoTitle() {
return (
<Image
style={{ width: 150, height: 50 }}
source={require('../../assets/logo-with-slogan.png')}
/>
);
}
function renderConfigBtn(_isAdmin) {
if (!_isAdmin) {
return (
<TouchableOpacity style={{ marginRight: 10 }} onPress={() => console.log('Configuraciones')} >
<Icon style={{ color: 'white' }} name='cog' size={30} />
</TouchableOpacity>
)
}
}
return (
<Stack.Navigator>
<Stack.Screen
name="MainMenu"
component={MainMenu}
options={{
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<View style={{ flexDirection: 'row' }}>
{renderConfigBtn(isAdmin)}
{renderUserMenu()}
</View>
),
headerStyle: { backgroundColor: '#0064c8' },
}}
/>
<Stack.Screen
name="Profile"
component={Profile}
options={{
headerStyle: { backgroundColor: '#0064c8' },
}}
/>
</Stack.Navigator>
)
}
export default MainStack;
Also, this stack is inside a navigation container as follows:
import React from 'react';
import { useSelector } from "react-redux";
import { NavigationContainer } from "#react-navigation/native";
import AuthStack from "./authStack";
import MainStack from "./mainStack";
const AppNavigator = props => {
const isAuth = useSelector(state => !!state.auth.access_token);
return (
<NavigationContainer>
{ !isAuth && <AuthStack/>}
{ isAuth && <MainStack/>}
</NavigationContainer>
);
};
export default AppNavigator;
I would appreciate any help.
You can access 'navigation' in options like below
options={({navigation})=>({
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<View style={{ flexDirection: 'row' }}>
{renderConfigBtn(isAdmin,navigation)}
{renderUserMenu(navigation)}
</View>
),
headerStyle: { backgroundColor: '#0064c8' },
})}
Basically you can pass a function as a prop to options and navigation will be passed to it as a parameter.
function renderUserMenu(navigation) {
return (
<TouchableOpacity style={{ marginRight: 20 }} onPress={() => navigation.navigate('YOUR SCREEN') } >
<Icon style={{ color: 'white' }} name='user-circle-o' size={30} />
</TouchableOpacity>
)
}
And you can change the renderUserMenu function like above so that it will do the navigation as required.
Use navigation options and then pass it to the function to navigate to profile:
<Stack.Screen
name="MainMenu"
component={MainMenu}
options={({ navigation }) => ({ ......
We simply can import the useNavigation hook from the react-navigation/native package and can implement navigation with the use of this hook without accessing the navigation props from the component.
For Ex.
First import the hook,
import { useNavigation } from '#react-navigation/native';
Use the hook to implement navigation as below in MainStack.js:
const navigation = useNavigation();
function renderUserMenu() {
return (
<TouchableOpacity style={{ marginRight: 20 }} onPress={() => navigation.navigate("Profile") } >
<Icon style={{ color: 'white' }} name='user-circle-o' size={30} />
</TouchableOpacity>
)
}

React Native Buttons onPress nothing happens, also onChangeText not working

I am new to React Native. I have a single login form with two fields. I want to authenticate the user before sending him to Dashboard.js. No matter what I try the button is not doing anything(absolutely nothing happens,no error). I have kept the code in Login.js to show all the things I have tried to do namely
routing to dashboard.js
trying to do something with invoking the handleSubmitPress function on button press.
pop an alert.
I have used two buttons. One from react-native-paper and one from react-native.
I am giving the code of my app.js and login.js below. Please can someone help?
CODE
App.js
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import DashBoard from "./mainmenu/DashBoard";
import Login from "./mainmenu/Login";
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="DashBoard" component={DashBoard} />
</Stack.Navigator>
</NavigationContainer>
);
}
Login.js
import React, { useState } from "react";
import { Title, TextInput} from "react-native-paper";
import { View, Alert,Button } from "react-native";
export default function Login() {
const [mobile, setMobile] = useState("123456789");
const [password, setPassword] = useState("123");
function handleSubmitPress() {
console.log({ mobile, password });
}
return (
<View
style={{
backgroundColor: "skyblue",
alignItems: "center",
justifyContent: "center",
}}
>
<TextInput
label="Your mobile number "
value={mobile}
onChangeText={(text) => setMobile(text)}
/>
<TextInput
label="Type Password "
value={password}
onChangeText={(text) => setPassword(text)}
/>
<Button
icon="camera"
type="submit"
mode="contained"
//onPress={() => props.navigation.navigate("DashBoard")}
onPress={()=>Alert.alert('Navigate pressed')}
>
Navigate
</Button>
<Button
title="Print"
onPress={() => Alert.alert('Simple Button pressed')}
// onPress={handleSubmitPress()}
/>
</View>
);
}
Change your Login component to this.
...
const Login = ({navigation}) => {
const [mobile, setMobile] = useState('123456789');
const [password, setPassword] = useState('123');
function handleSubmitPress() {
console.log({mobile, password});
}
return (
<View
style={{
backgroundColor: 'skyblue',
alignItems: 'center',
justifyContent: 'center',
}}>
<TextInput
label="Your mobile number "
value={mobile}
onChangeText={text => setMobile(text)}
/>
<TextInput
label="Type Password "
value={password}
onChangeText={text => setPassword(text)}
/>
<Button
title="title"
icon="camera"
type="submit"
mode="contained"
onPress={() => navigation.navigate('DashBoard')}>
Navigate
</Button>
<Button title="Print" onPress={() => handleSubmitPress()} />
</View>
);
};
export default App;
There were a couple problems.
I've used the default React Native buttons. So I added a title prop to one of the buttons, because that's required. I gave it the value "title", but change this to what you want or use the React Native Paper buttons.
The main problem was how you called handleSubmitPress in your button onPress.
Your onChangeText was fine, you just couldn't see the result, because the handleSubmitPress wasn't being called.
I've also used destructuring so you're able to access the navigation prop directly. You can also do const Long = (props) => {...} and use props.navigation, but either way you need to pass in something otherwise navigation will not work.

React navigation hide one tab

I'm using react-navigation for navigating between screens. Is it possible to have createBottomTabNavigator with 3 tabs, but when you show tab bar, I want to have visible only 2 tabs instead of 3. ?
I made a npm package for this, please see;
https://www.npmjs.com/package/react-navigation-selective-tab-bar
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow
*/
import React, { Component } from "react";
import { Platform, StyleSheet, Text, View, Button } from "react-native";
import { createBottomTabNavigator, createAppContainer } from "react-navigation";
import BottomTabBar from "react-navigation-selective-tab-bar";
class ScreenOne extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen One</Text>
<Text style={styles.number}>1</Text>
<Text style={styles.instructions}>
I AM on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenTwo extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Two</Text>
<Text style={styles.number}>2</Text>
<Text style={styles.instructions}>
I am NOT on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenThree extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Three</Text>
<Text style={styles.number}>3</Text>
<Text style={styles.instructions}>
I AM on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenFour extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Four</Text>
<Text style={styles.number}>4</Text>
<Text style={styles.instructions}>
I am NOT on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5
},
number: {
fontSize: 50
},
buttons: {
flexDirection: "row"
}
});
const AppNavigator = createBottomTabNavigator(
{
One: {
screen: ScreenOne
},
Two: {
screen: ScreenTwo
},
Three: {
screen: ScreenThree
},
Four: {
screen: ScreenFour
}
},
{
tabBarComponent: props => {
return (
<BottomTabBar
{...props} // Required
display={["One", "Three"]} // Required
background="black" // Optional
/>
);
}
}
);
export default createAppContainer(AppNavigator);
https://github.com/react-navigation/react-navigation/issues/5230#issuecomment-649206507
Here is how you can tell the tab navigator to not render certain routes.
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarButton: [
"Route1ToExclude",
"Route2ToExclude"
].includes(route.name)
? () => {
return null;
}
: undefined,
})}
>
This worked for me, you are still able to navigate to the tab! I changed it to this:
Without a variable:
tabBarButton: ["About"].includes(route.name) ? () => null : undefined
With a variable to hide specific tabs:
const hiddenTabs = ["About", "Food"];
tabBarButton: hiddenTabs.includes(route.name) ? () => null : undefined
With a variable to show specific tabs only:
const tabsToShow = ["About", "Food"];
tabBarButton: !tabsToShow.includes(route.name) ? () => null : undefined
All credit goes to Ben Awad!
Put your third item/screen in a stack navigator:
const Bottom = createBottomTabNavigator({
item1: {screen: Screen1},
item2: {screen: Screen2},
},{
initialRouteName: "item1",
}
)
export default createStackNavigator({
tabs: Bottom,
item3: Screen3,
})
At last, to change the screen to your third route in your component, you can do this:
// ...
import {withNavigation} from 'react-navigation' // IMPORTANT
export default class Example extends React.Component{
render(){
return(
<TouchableOpacity onPress={() => this.props.navigation.navigate('item3')}>
)
}
}
export default withNavigation(Example) // IMPORTANT
For example, if you want to have 5 active routes in a createBottomTabNavigator, but only 3 or another number to show icons in the TabBar. In this case, all 5 routes will be active, and you can go to them props.navigation.navigate()
You must pass a filtered list of routes to the TabBar component, but the object must be sure to be deeply copied (using lodash for example)
import cloneDeep from 'lodash/cloneDeep';
....
const TabBarComponent = props => {
const routeNamesToHide = [
'MyOfficeStack',
'ArenaStack',
'SavedSearchesStack',
'NotificationsStack',
];
// Delete from TABBAR items in array 'routeNamesToHide'
let newNavigation = cloneDeep(props.navigation);
newNavigation.state.routes = newNavigation.state.routes.filter(
item => !routeNamesToHide.includes(item.routeName)
);
//
return <BottomTabBar {...props} navigation={{ ...newNavigation }} />;
};
const tabNavigator = createBottomTabNavigator(
{
SearchStack,
FavouritesStack,
AddScreenStack,
MessagesStack,
BookingsStack,
MyOfficeStack,
AreaStack,
SavedSearchesStack,
NotificationsStack,
},
{
lazy: false,
tabBarOptions: {
showLabel: true,
},
tabBarComponent: props => (
<TabBarComponent {...props} />
),
}
);
the easiest solution is this
<Tab.Screen
name='someroute'
component={SomeComponent}
options={{
tabBarButton: props => null,
}}
/>
this is by far the best solution because it doesn't require extra effort
Ben Awad solution(mentioned by Kayden van Rijn) is good, it allows centralized control, but you need extra effort to make sure the type of the route name array is correct
<Tab.Navigator
screenOptions={({ route }) => {
const toExclude: typeof route.name[] = ['routeName']
return {
tabBarButton: toExclude.includes(route.name)
? () => {
return null
}
: undefined,
}
}}
>
credit