Calling a function from React navigation header (getParam is not a function) - javascript

I have this icon that needs to run a function onLogout in a separate file
First I tried passing navigation param to bottomTab options like so
<BottomTab.Screen
name="Settings"
component={Settings}
options={(navigation) => ({
title: "Settings",
tabBarIcon: () => <Icon name="settings" size={20} color="black" />,
headerRight: (
<Icon
onPress={navigation.getParam('onLogout')}
style={{ marginRight: 14 }} name="log-out" size={18} color="black" />
)
})}
/>
In the settings screen where the function lives I have initialized the function like so
this.props.navigation.setParams({ onLogout: this.onLogout });
I have tried inside componentDidMount and componentWillMount
Also tried to bind it
constructor(props) {
super(props);
this.onLogout = this.onLogout.bind(this);
}
TypeError: navigation.getParam is not a function. (In
'navigation.getParam('onLogout')', 'navigation.getParam' is undefined)
At one point the function get executed but without me touching the icon but I changed to this
this.props.navigation.setParams({ onLogout: this.onLogout() });
Since that didn't work I tried writing the options in the file itself
export default class Settings extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerRight: (
<Icon
// onPress={navigation.getParam('onLogout')}
style={{ marginRight: 14 }} name="log-out" size={18} color="black" />
)
};
};
...
No icon shows up on the screen and nothing works with that method (title, ect...)

Try this :
<BottomTab.Screen
name="Settings"
component={Settings}
options={(props) => ({
title: "Settings",
tabBarIcon: () => <Icon name="settings" size={20} color="black" />,
headerRight:() =>(
<Icon
onPress={()=>props.route.params.onLogout()}
style={{ marginRight: 14 }} name="log-out" size={18} color="black" />
)
})}
/>

Related

Render header right button conditionally with React Navigation in React Native

I am trying to conditionally render the Entypo new-message icon in the right header based on a boolean variable (if the variable is true, then the icon will show up in the header). Please see the minimum reproducible code below. Thanks in advance.
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { Ionicons, MaterialCommunityIcons, Entypo } from "#expo/vector-icons";
const Tab = createBottomTabNavigator();
const MainTabNavigator = () => {
return (
<Tab.Navigator
initialRouteName="Chats"
screenOptions={{
tabBarStyle: { backgroundColor: "whitesmoke" },
headerStyle: { backgroundColor: "whitesmoke" },
}}
>
<Tab.Screen
name="Chats"
component={ChatsScreen}
options={({ navigation }) => ({
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons
name="message-processing-outline"
size={size}
color={color}
/>
),
headerRight: () => (
<Entypo
onPress={() => navigation.navigate("Contacts")}
name="new-message"
size={18}
color={"royalblue"}
style={{ marginRight: 15 }}
/>
),
})}
/>
</Tab.Navigator>
);
};
export default MainTabNavigator;
You can do it as below, with a Conditional (ternary) operator. Just replace boleanVariable with your actual variable.
options={({ navigation }) => ({
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="message-processing-outline" size={size} color={color} />
),
headerRight: () =>
!boleanVariable ? (
<></>
) : (
<Entypo
onPress={() => navigation.navigate("Contacts")}
name="new-message"
size={18}
color={"royalblue"}
style={{ marginRight: 15 }}
/>
),
})}

Undefined is not an object (evaluating 'route.params.title')

I followed the React Navigation Doc to achieve a Dynamic header title change but It shows the error Undefined is not an object (evaluating 'route.params.title').
My tabs.js:
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<HomeStack.Screen
name="Profile"
component={Profile}
options={({ route }) => ({ title: route.params.title })}
/>
</HomeStack.Navigator>
);
}
The Home.js has the onpress like that:
<TouchableOpacity
onPress={() => {
navigation.navigate('Profile', {
title: 'Custom title',
});
}}
>
And Profile.js:
function Profile({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello</Text>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
Add a check/default value on your params, because route.params is not always valorized, but only when you navigate on that page.
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<HomeStack.Screen
name="Profile"
component={Profile}
options={({ route }) => ({ title: route.params?.title || "DEFAULT TITLE" })}
/>
</HomeStack.Navigator>
);
}

Trying to push StackScreen in React Native

Whenever I activate the onPress method by tapping on a message, the MessageScreen component just re-renders rather than displaying ChatScreen. This happens even if I replace ChatScreen with any other screen. Any help on the matter is much appreciated.
App.js
<NavigationContainer ref={containerRef} initialState={initialNavigationState}>
<Drawer.Navigator>
<Drawer.Screen name="Feed" component={BottomTabNavigator} options={{swipeEnabled: false}} />
<Drawer.Screen name="Settings" component={SettingsStack} options={{swipeEnabled: false}} />
</Drawer.Navigator>
</NavigationContainer>
BottomTabNavigator
const BottomTab = createBottomTabNavigator();
export default function BottomTabNavigator({ navigation, route }) {
{...HomeStack Code}
{...ProfileStack Code}
const MyMessagesStack = createStackNavigator();
function MessagesStack() {
return (
<MyMessagesStack.Navigator initialRouteName={"Messages"}
screenOptions={{headerShown: false}}>
<MyMessagesStack.Screen name="Messages" component={MessagesScreen} />
<MyMessagesStack.Screen name="Chats" component={ChatScreen} />
</MyMessagesStack.Navigator>
);
}
return (
<BottomTab.Navigator initialRouteName={INITIAL_ROUTE_NAME} >
<BottomTab.Screen
name="Home"
component={HomeStack}
options={{title: 'Feed'}}
/>
<BottomTab.Screen
name="Messages"
component={MessagesStack}
options={{title: 'Messages'}}
/>
<BottomTab.Screen
name="Profile"
component={ProfileStack}
options={{title: 'Profile'}}
/>
</BottomTab.Navigator>
);
}
MessageScreen.js
//flatscreen to render message components
</View>
<FlatList
data={Data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => props.navigation.navigate('Chats')} >
<Message
image={item.image}
name={item.name}
lastMessage={item.message}
timeStamp={item.timestamp}
opened
/>
</TouchableOpacity>
)}
/>
The reason your components are remounting is because there are components defined inside other components:
function BottomTabNavigator() {
// Here
function MessagesStack() {
// ...
}
// ...
}
You need to define them outside to avoid that:
function MessagesStack() {
// ...
}
function BottomTabNavigator() {
// ...
}

How to define custom header inside screen in react navigation 5?

i know we use options prop when we define screen in root file
<Stack.Screen
name="index"
component={Index}
options={({ navigation, route }) => ({
headerRight: (props) => (
<MaterialIcons name="add" size={30} style={{ marginRight: 20 }} />
),
})}
/>
But i want to define in the screen by itself like we used to do in react navigation 4
Index.navigationOptions = () => {
return {
headerRight: (
<MaterialIcons name="add" size={30} style={{ marginRight: 20 }} />
),
};
};
but how i can do it in react navigation 5?
use navigation.setOptions
function HomeScreen({ navigation }) {
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<MaterialIcons name="add" size={30} style={{ marginRight: 20 }} />
),
});
}, [navigation]);

Hide a header of a BottomTabNavigator from a StackNavigator in react-navigation

I'm trying to hide a header in a BottomTabNavigator but this one came from a StackNavigator. I already tried to use the header: null inside the page and other ways but nothing works!
const AppTabNav = createBottomTabNavigator({
HomeScr:{
screen:Home,navigationOptions:{tabBarLabel:'Inicio',tabBarIcon: ({tintColor}) => (<Icon name='home' color={tintColor} size={25}/>)}
},
Settings:{
screen:Config,navigationOptions:{ tabBarLabel:'Configurações',tabBarIcon:({ tintColor })=>(<Icon name="settings" color={tintColor} size={25}/>)}
}
})
const AppStackNavigator = createStackNavigator({
AppTab:{
screen:AppTabNav,
navigationOptions:({navigation}) =>({
title:'Bem vindo #USER',
headerLeft:(
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<View style={{paddingHorizontal:10}}>
<Icon name="menu" color='black' size={24}/>
</View>
</TouchableOpacity>)
})
}
},{tabBarOptions:{
activeTintColor:'blue',
inactiveTintColor:'black'
}})
This is the header I want to hide when I click on configurações in the Bottombar
Imagem
This is the code of the Config.js file
export default class Config extends Component {
static navigationOptions = {
header: null,
drawerIcon: ({ tintColor }) => ( <Icon name='settings' style={{color:tintColor ,fontSize:24}} />)
}
SignOut = async() => {
AsyncStorage.clear()
this.props.navigation.navigate('AuthLoading')
}
render() {
return (
<Container>
<Header>
<Left style={{flex:1}}>
<Icon name="menu" color='black' size={24} onPress={() => this.props.navigation.openDrawer()}/>
</Left>
<Body style={{flex: 1,justifyContent: 'center'}}>
<Title>Configurações</Title>
</Body>
<Right style={{flex:1}}/>
</Header>
<View style={{flex :1, alignItems:'center', justifyContent:'center'}}>
<Text>Configurações</Text>
</View>
</Container>
);
}
}
Just add this into your component code and Header will be hidden
tabBarVisible: false
export default class Config extends Component {
static navigationOptions = {
tabBarVisible: false,
drawerIcon: ({ tintColor }) => ( <Icon name='settings' style={{color:tintColor ,fontSize:24}} />)
}
SignOut = async() => {
AsyncStorage.clear()
this.props.navigation.navigate('AuthLoading')
}
render() {
return (
<Container>
<Header>
<Left style={{flex:1}}>
<Icon name="menu" color='black' size={24} onPress={() => this.props.navigation.openDrawer()}/>
</Left>
<Body style={{flex: 1,justifyContent: 'center'}}>
<Title>Configurações</Title>
</Body>
<Right style={{flex:1}}/>
</Header>
<View style={{flex :1, alignItems:'center', justifyContent:'center'}}>
<Text>Configurações</Text>
</View>
</Container>
);
}
}

Categories