Implemented HeaderBackButtons by React Navigation in React Native and some of them are too far on the right
Hello,
can someone explain, why the HeaderBackButton is so far on right?
I also use this on other screens and it looks normal.
Implemented it like this:
import { HeaderBackButton } from "#react-navigation/elements";
useEffect(() => {
navigation.setOptions({
headerLeft: () => (
<HeaderBackButton onPress={() => navigation.goBack()} />
),
});
}, []);
And here are two screenshots of different screens:
1
2
Thank you!
Related
Here is my code:
<Drawer.Screen
name="Home"
component={StackNavigator}
options={({route}) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Billing';
if (sideMenuDisabledScreens.includes(routeName))
return {swipeEnabled: false};
}}
/>
I am implementing drawer navigator in my application and I want to add icon for drawer item home. Inside options I have added route to disable drawer for particular screens. After adding the route disable code I am not able to mention icons for drawerIcon. How can I do this?
i get your point, you can have both properties just like this
options={({route}) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Billing';
if (sideMenuDisabledScreens.includes(routeName))
return {swipeEnabled: false};
},
{
drawerIcon: // add your comp here,
title:" THIS is possible",
}
}
Hope ite helps. feel free for doubts
Add drawerIcon property like the following:
drawerIcon: ({ tintColor }) => (
<Image
source={require('./chats-icon.png')}
style={[{ tintColor: tintColor }]}
/>
),
There are many similar questions that have been answered but none of them uses the newest react-navigation version.
I want to go to the 'Home' screen from the 'Document' screen on back button press. This is what I tried but it doesn't work.
<NavigationContainer>
<Stack.Navigator initialRouteName="Home" screenOptions={{ headerShown : false }}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Camera" component={CameraScreen} />
<Stack.Screen name="Document" component={Document} options={{
headerLeft: (props) => (<HeaderBackButton {...props} onPress={() => props.navigation.navigate("Home")}/>)
}} />
</Stack.Navigator>
</NavigationContainer>
Edit for more clarification: My app starts with 'Home' then goes to 'Camera' then to 'Document'. Now, I don't want to go back to 'Camera' once I am at 'Document' rather straight to 'Home' when I press the phone's back button.
According to the documentation, this is how to override the back button.
<Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: (props) => (
<HeaderBackButton
{...props}
onPress={() => {
// Do something
}}
/>
),
}}/>;
But I don't know how to go to 'Home' using the above code. So I searched similar questions and most of them had navigationOptions and other stuff. I tried following the below answer from a question.
import { HeaderBackButton } from 'react-navigation';
static navigationOptions = ({navigation}) => {
return{
headerLeft:(<HeaderBackButton onPress={()=>{navigation.navigate('A')}}/>)
}
}
So yeah, the back button doesn't respond even if I use console.log
You can customise back button behaviour using navigation 'beforeRemove' event, which fires before unloading a screen.
useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', e => {
e.preventDefault(); // Prevent default action
unsubscribe() // Unsubscribe the event on first call to prevent infinite loop
navigation.navigate('Home') // Navigate to your desired screen
});
}, [])
The positive point with this approach is that it will fire on any type of back navigation, whether it's in-app back button or device back button/gesture.
Navigation Events Doc
I managed to achieve what I needed. I had to override the physical back button in 'Document'.
useFocusEffect(
useCallback(() => {
const onBackPress = () => {
navigation.pop(2); // remove two screens i.e. Document and Camera
return true // disable normal behaviour
};
BackHandler.addEventListener('hardwareBackPress', onBackPress); // detect back button press
return () =>
BackHandler.removeEventListener('hardwareBackPress');
}, [])
);
I am not sure how your code works.
<it doesn't work.> - you can give us more information.
But it's worth to try below.
import {CommonActions} from '#react-navigation/native';
props.navigation.dispatch(
CommonActions.navigate({name: 'Home'}),
);
https://reactnavigation.org/docs/navigation-prop/#dispatch
Did you try CommonActions.reset ?
something like this from the doc :
import { CommonActions } from '#react-navigation/native';
// when you want to navigate to the Documents page, instead of doing
navigation.navigate({routeName: 'Documents'});
// you can try
navigation.dispatch(
CommonActions.reset({
index: 1,
routes: [
{ name: 'Home' },
{
name: 'Documents',
params: { name: 'abc' },
},
],
})
);
So that when you're going back from Documents you're heading to the previous screen in the stack : Home.
In the following simplified example, a user updates the label state using the TextInput and then clicks the 'Save' button in the header. In the submit function, when the label state is requested it returns the original value '' rather than the updated value.
What changes need to be made to the navigation headerRight button to fix this issue?
Note: When the Save button is in the render view, everything works as expected, just not when it's in the header.
import React, {useState, useLayoutEffect} from 'react';
import { TouchableWithoutFeedback, View, Text, TextInput } from 'react-native';
export default function EditScreen({navigation}){
const [label, setLabel] = useState('');
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableWithoutFeedback onPress={submit}>
<Text>Save</Text>
</TouchableWithoutFeedback>
),
});
}, [navigation]);
const submit = () => {
//label doesn't return the updated state here
const data = {label: label}
fetch(....)
}
return(
<View>
<TextInput onChangeText={(text) => setLabel(text) } value={label} />
</View>
)
}
Label should be passed as a dependency for the useLayouteffect, Which will make the hook run on changes
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableWithoutFeedback onPress={submit}>
<Text>Save</Text>
</TouchableWithoutFeedback>
),
});
}, [navigation,label]);
Guruparan's answer is correct for the question, although I wanted to make the solution more usable for screens with many TextInputs.
To achieve that, I added an additional state called saving, which is set to true when Done is clicked. This triggers the useEffect hook to be called and therefore the submit.
export default function EditScreen({navigation}){
const [label, setLabel] = useState('');
const [saving, setSaving] = useState(false);
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableWithoutFeedback onPress={() => setSaving(true)}>
<Text>Done</Text>
</TouchableWithoutFeedback>
),
});
}, [navigation]);
useEffect(() => {
// Check if saving to avoid calling submit on screen unmounting
if(saving){
submit()
}
}, [saving]);
const submit = () => {
const data = {label: label}
fetch(....)
}
return(
<View>
<TextInput onChangeText={(text) => setLabel(text) } value={label} />
</View>
)
}
Currently, I was taking a course:Multiplatform Mobile App Development with React Native in coursera, and I was stuck at after every lecture because the instructor use react-navigation#2.0.1 but I want to make sure to learn the latest version(v5). In this lecture he created a stack navigator and bring an icon to a screen like,
import {createStackNavigator} from 'react-navigation';
import { Icon } from 'react-native-elements';
const MenuNavigator = createStackNavigator(
{
Menu: {
screen: Menu,
navigationOptions: ({ navigation }) => ({
headerLeft: (
<Icon
name="menu"
size={24}
color="white"
onPress={() => navigation.toggleDrawer()}
/>
),
}),
},
Dishdetail: { screen: Dishdetail },
},
{
initialRouteName: 'Menu'
}
);
Where navigationOptions can be an object or be a function that takes in props.
I convert it like,
import { createStackNavigator } from '#react-navigation/stack';
import { Icon } from 'react-native-elements';
const MenuNavigator = createStackNavigator();
function MenuNavigatorScreen() {
return (
<MenuNavigator.Navigator
initialRouteName="Menu"
screenOptions={HeaderOptions}
>
<MenuNavigator.Screen
name="Menu"
component={Menu}
/>
<MenuNavigator.Screen
name="Dishdetail"
component={Dishdetail}
options={{ headerTitle: 'Dish Detail' }}
/>
</MenuNavigator.Navigator>
);
}
But I was confused how to convert the navigationOptions functionality into my code. Because their docs didn't tell how to trun my options object into a function to bring the navigation prop?
One more thing is he was using drawerIcon,
const MainNavigator = createDrawerNavigator(
{
navigationOptions: {
drawerLabel: 'Login',
drawerIcon: ({ tintColor }) => (
<Icon
name="sign-in"
type="font-awesome"
size={24}
color={tintColor}
/>
),
}
...
But I didn't find anything related drawerIcon in Drawer navigation docs
I heartily thank if anyone helps me to figure out this.
First of all, The options prop can be used to configure individual screens inside the navigator. And headerLeft is a function that returns a React element to display on the left side of the header. When a function is used, it receives several arguments when rendered (onPress, label, labelStyle, and more - check types.tsx for the complete list).
options = {
({
navigation
}) => ({
headerLeft: () => ( <
Icon name = 'menu'
size = {
24
}
color = 'white'
onPress = {
() =>
navigation.toggleDrawer()
}
/>
)
})
}
And for drawerIcon use:
options = {
{
drawerIcon: ({
tintColor
}) => ( <
Icon name = 'home'
type = 'font-awesome'
size = {
24
}
color = {
tintColor
}
/>
)
}
}
I am new in React native development,I have completed drawer functionality using following tutorial and github example:-
Drawer Git hub link
Drawer Tutorial link
So,According to above link Drawer component has one disable parameter which is helpful to lock drawer.
In my case,I have:-
Login Page :- So I am trying to lock the drawer when user is not logged into system.
Home Page :- So when ever user logged in successfully,I have open this page and unlock my drawer.
Added render() method for reference:-
render() {
<Drawer
ref={(ref) => this._drawer = ref}
disabled={!this.state.drawerEnabled}
type="overlay"
content={<Menu navigate={(route) => {
this._navigator.push(navigationHelper(route));
this._drawer.close()
}}/>}
tapToClose={true}
openDrawerOffset={0.2}
panCloseMask={0.2}
closedDrawerOffset={-3}
styles={{
drawer: {shadowColor: '#000000', shadowOpacity: 0.8, shadowRadius: 3},
main: {paddingLeft: 3}
}}
tweenHandler={(ratio) => ({
main: { opacity:(2-ratio)/2 }
})}>
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={(route) => Navigator.SceneConfigs.FloatFromLeft}
initialRoute={{
id: 'Login',
title: 'Login',
index: 0
}}
renderScene={(route, navigator) => this._renderScene(route, navigator)}
navigationBar={
<Navigator.NavigationBar
style={styles.navBar}
routeMapper={NavigationBarRouteMapper} />
}
/>
</Drawer>
);
}
So,My problem is:-
disabled parameter is not working.I have tried with `setState()' function also but the result is same.
Please suggest me other drawer examples/tutorials which works in above case.
I think React Navigation library is best option. Which is fully customizable and supported both Android and IOS. You should use Drawer Navigator, can get documentation here.
Here I am adding code sample, that How I am locked/unlocked the drawer.
Here StackApp will be your Stack Navigator which contain all the
drawer pages.
StackApp.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed'; //For child page it will lock drawer
}
return {
drawerLockMode
};
};
const DrawerStack = createDrawerNavigator({
StackHome: {screen: StackApp},
// Auth: {screen: AuthScreen},
}
,{
drawerWidth:width*0.8,
contentComponent: (props) =>
<ScrollView>
<Menu {...props}/>
</ScrollView>
});
check react native documentation and find 'drawerLockMode'