React navigation V5 header button usage - javascript

I have react navigation screen as follows .
<Stack.Screen name="Home" component={HomeScreen} />
I need to navigate another screen using a right header button how can i do this.
I'am using react navigation V5

This might help
function StackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="#fff"
/>
),
}}
/>
</Stack.Navigator>
);
}
You can also use screenOptions
screenOptions={({route, navigation}) => ({
headerStyle: {
backgroundColor: '#f4511e',
},
headerRight: () => (
<Button
// only alert is ok, the other is error.
onPress={() => navigation.navigate('Home')}
title="Logout"
color="#fff"
/>
),
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
})}

Related

Pass navigation in props to menu element in React Native and React Navigation

I'm adding a menu to every screen navigation header, so created a menu function that needs the navigation object to navigate to different screens based on the menu item tapped. But the navigation.navigate from props is undefined.
export default function GeneralMenu(props) {
const [showMenu, setShowMenu] = useState(false);
return (
<View style={{}}>
<Menu
visible={showMenu}
onDismiss={() => setShowMenu(false)}
anchor={
<TouchableOpacity onPress={() => setShowMenu(true)}>
<MaterialCommunityIcons
name="menu"
size={30}
style={{ color: 'white' }}
/>
</TouchableOpacity>
}>
<Menu.Item onPress={() => { console.log(props.navigation)}} title="Screen1" />
<Menu.Item onPress={() => {props.navigation.navigate('Screen1', {})}} title="Screen1" />
</Menu>
</View>
);
Then I use it like this:
return (
<Provider>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeComponent}
options={{ title: 'Home',
headerTitleAlign: 'center',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: 'red'
},
headerRight: (navigation) => <GeneralMenu navigation={navigation} />,
}}
/>
...
...
</NavigationContainer>
</Provider>
);
The console.log() when first menu item is tapped shows:
Object {
"canGoBack": false,
"tintColor": "#fff",
}
As you see there is no navigate property. Please, any idea what I'm doing wrong?
To get navigation.navigate() you would wanna use the function syntax of options, which receives an object that contains navigation, like so:
<Stack.Screen
name="Home"
component={HomeComponent}
options={({ navigation }) => ({
title: "Home",
headerTitleAlign: "center",
headerTintColor: "#fff",
headerStyle: {
backgroundColor: "red",
},
headerRight: () => <GeneralMenu navigation={navigation} />,
})}
/>
I'm not sure why you are passing navigation through props. But for react-navigation to navigate to other screens (even from the components that are not screen themselves), you don't need to pass them through props.
You can basically access navigation object itself by using useNavigation hook like this:
const navigation = useNavigation();
and then wherever you need to use it, you can use it normally like:
navigation.navigate(Screen name goes here);
its happen because u shadowing name props, it should be
<Menu.Item onPress={() => { console.log(props.navigation)}} title="Screen1" />
<Menu.Item onPress={() => {props.navigation.navigate('Screen1', {})}} title="Screen1" />
Also
header right doesn't have navigation props
It should be like this
return (
<Provider>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeComponent}
options={(navigation) => {
return { title: 'Home',
headerTitleAlign: 'center',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: 'red'
},
headerRight: () => <GeneralMenu navigation={navigation} />,
}
}}
/>
...
...
</NavigationContainer>
</Provider>
);

React Navigation 6.0 double header issue

I have same code structure of navigation of React Navigation 5.x
...
"#react-navigation/bottom-tabs": "^5.11.11",
"#react-navigation/native": "^5.9.4",
"#react-navigation/stack": "^5.14.5",
...
i upgraded React Navigation 5 to 6.x
"#react-navigation/bottom-tabs": "^6.0.5",
"#react-navigation/native": "^6.0.2",
"#react-navigation/stack": "^6.0.7",
When i run the code i got double header, above one header name is Tabs Screen name and below one is headerTitle name
These is the code structure of my navigation
const HomeStack = createStackNavigator();
const HomeStackScreen = ({navigation, props}) => (
<HomeStack.Navigator>
<HomeStack.Screen
name="HomeMain"
component={HomeMain}
options={{
headerTitle: 'Delivery App',
}}
/>
<HomeStack.Screen
name="Search"
component={Search}
options={{
headerTitle: 'Search',
headerTitleStyle: {
fontFamily: 'Muli-Regular',
},
}}
/>
...
</HomeStack.Navigator>
);
const CartStack = createStackNavigator();
const CartStackScreen = () => (
<CartStack.Navigator>
<CartStack.Screen
name="CART"
component={Cart}
options={({route}) => ({
headerTitleStyle: {
fontFamily: 'Muli-Regular',
},
})}
/>
...
</CartStack.Navigator>
);
const ProfileStack = createStackNavigator();
const ProfileStackScreen = () => (
<ProfileStack.Navigator>
<ProfileStack.Screen
name="ProfileMain"
component={ProfileMain}
options={({route}) => ({
headerTitle: 'Profile' /*headerShown: false*/,
headerTitleStyle: {
fontFamily: 'Muli-Regular',
},
})}
/>
...
</ProfileStack.Navigator>
);
const AppTabs = createBottomTabNavigator();
const AppTabsScreen = props => {
return (
<AppTabs.Navigator
tabBarOptions={{
activeTintColor: '#00D084',
inactiveTintColor: '#C6CDD7',
}}>
<AppTabs.Screen
name="Home" //<------ This name is showing conflict is here
component={HomeStackScreen}
options={{
tabBarIcon: props => (
<Icon.Ionicons name="home" size={props.size} color={props.color} />
),
}}
/>
<AppTabs.Screen
name="Cart"
component={CartStackScreen}
options={{
tabBarIcon: props => (
<Icon.Ionicons name="cart" size={props.size} color={props.color} />
),
tabBarBadge: props.cartCount,
}}
/>
<AppTabs.Screen
name="Account"
component={ProfileStackScreen}
options={{
tabBarIcon: props => (
<Icon.Ionicons
name="person"
size={props.size}
color={props.color}
/>
),
}}
/>
</AppTabs.Navigator>
);
};
Where do we change to fix this issue, i have tried headerShow null or false also but it hide only 2nd Header. I want to hide the 1st one.
Here is the screenshot
You need to add headerShown: false to the Tab Navigator.
e.g.
<AppTabs.Navigator
screenOptions: {{ headerShown: false }}
tabBarOptions={{
activeTintColor: '#00D084',
inactiveTintColor: '#C6CDD7',
}}>
{...code}
</AppTabs.Navigator/>
That is if you want to remove the header added by the Tab Navigation. You can do the same for Stack navigators if you want to remove that one.
If you don't want to remove header from all of the tab navigators, you can individually add it like this:
<AppTabs.Screen
name="Account"
component={ProfileStackScreen}
options={{
headerShown: false
// other options
}}
/>
And that will remove header from only that tab.
Ref: https://reactnavigation.org/docs/headers
I have resolved my issue by this line of code.
<Tab.Navigator
initialRouteName="Home"
screenOptions={{tabBarActiveTintColor:Colors.appPurple,headerShown:false}}>
{...code} </Tab.Navigator>

React Native Navigation Drawer Problem ('navigation.openDrawer' is undefined))

Hi guys i'm new to react native. I want to use drawer navigation with menu button. But actually i don't understand react navigation very well probably. When i press button for openDrawer i'm getting error like this;
TypeError: navigation.openDrawer is not a function. (In 'navigation.openDrawer()', 'navigation.openDrawer' is undefined)
This is My Snack Example ; https://snack.expo.io/#vubes/drawer-check
Here is useful part of my code. Maybe you can understand my problem.
Thanks in advance to anyone who can help.
function DovizStack({navigation}) {
return (
<Stack.Navigator
initialRouteName="Döviz"
screenOptions={{
headerStyle: { backgroundColor: "#1D1D1D" },
headerTintColor: "#fff",
headerTitleStyle: { fontWeight: "bold" },
}}
>
<Stack.Screen
name="Doviz"
component={Doviz}
options={{
title: "Döviz",
headerTitleAlign: "center",
headerLeft: () => (<TouchableOpacity style={{paddingLeft:20}} onPress={()=> navigation.openDrawer()}>
<MaterialCommunityIcons name="menu" color={"white"} size={20} />
</TouchableOpacity>),
}}
/>
<Stack.Screen
name="dovizBuyDetails"
component={dovizBuyDetails}
options={{ title: "Alış", headerTitleAlign: "center" }}
/>
<Stack.Screen
name="dovizSellDetails"
component={dovizSellDetails}
options={{ title: "Satış", headerTitleAlign: "center" }}
/>
</Stack.Navigator>
);
}
I have 5 stack like this. After that comes the myTab.
drawerStack ;
function DrawerStack() {
return(
<Drawer.Navigator initialRouteName="Menu" drawerPosition= "right" >
<Drawer.Screen name="stack" component={stack} />
<Drawer.Screen name="Doviz" component={DovizStack}/>
<Drawer.Screen name="Altın" component={AltinStack} />
</Drawer.Navigator>
)
}
and default stack ;
export default function stack() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
options={{ headerShown: false }}
name="Giriş"
component={LandingStack}
/>
<Stack.Screen
options={{ headerShown: false }}
name="drawer"
component={myTab}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Actually i can run drawer with landingscreen(login page,register) but i don't want to display without login
navigation in not defined in your scope.
use options as function and receive navigation see here.
your code should look like this:
<Stack.Screen
options={({ navigation }) => ({ //receive navigation here
//navigation is defined now you can use it
headerLeft: () => (
<TouchableOpacity
style={{paddingLeft:20}}
onPress={()=> navigation.openDrawer()}>
<MaterialCommunityIcons name="menu" color={"white"} size={20} />
</TouchableOpacity>),
})}
/>
EDIT :
see full example(open drawer menu from nested stack navigation) try snack here
import * as React from 'react';
import { Button, View, Text, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
function ProfileScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
</View>
);
}
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
function DovizStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Profile"
options={({ navigation }) => ({ //receive navigation here
headerLeft: () => (
<TouchableOpacity style={{paddingLeft:20}} onPress={()=> navigation.openDrawer()}>
<Text>open</Text>
</TouchableOpacity>),
})
}
component={ProfileScreen} />
</Stack.Navigator>
);
}
function DrawerStack() {
return(
<Drawer.Navigator initialRouteName="Doviz">
<Drawer.Screen name="Doviz" component={DovizStack}/>
</Drawer.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<DrawerStack/>
</NavigationContainer>
);
}

React Native: the app crashes when I go back from one screen to another

I am building an application project with react native. The video of the problem:
https://imgur.com/a/xz0vMw7 (>2MB)
In short, the app has two separate searches, the first searches for the lyrics of a song, the second the biography of the artist. The problem is when I try to switch from the song page to the artist page, in fact going back the app crashes.
Stack Navigator on App.js:
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="MyMusic"
component={TabNavigator}
options={{
title: 'MyMusic',
headerStyle: {
backgroundColor: '#673AB7',
},
headerTintColor: 'white',
}}
/>
<Stack.Screen
name="Search song"
component={SongScreen}
options={{
title: 'Search Song',
headerStyle: {
backgroundColor: '#673AB7',
},
headerTintColor: 'white',
}}
/>
<Stack.Screen
name="Search artist"
component={ArtistScreen}
options={{
title: 'Search Artist',
headerStyle: {
backgroundColor: '#673AB7',
},
headerTintColor: 'white',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
passing through Artist Info on SongScreen.js:
function SongScreen({ route, navigation }) {
//...
const RightCardContent = () =>
<View style={{margin: '8%'}}>
<Button
title='ARTIST INFO'
color='#673AB7'
onPress={() => navigation.navigate('Search artist', textArtist)}
/>
</View>
//...
return (
//...
<Card>
<Card.Title
title={songName}
subtitle={artistName}
left={LeftCardContent}
right={RightCardContent}
/>
</Card>
//...
)}

React Native v5: Cannot receive updated route.params from another screen component using navigation.navigate()

I'm trying to update route.params everytime a screen submits a form that sends data to another screen that shows this submitted data. But it just navigates and route.params remains undefined. Here is my navigation architecture.
Drawer => Tab => Stack (for each tab)
App.js
return (
<>
<NavigationContainer>
<Drawer.Navigator
drawerContent={(props) => <DrawerContent {...props} />}
>
<Drawer.Screen
name="Main"
component={BottomTabScreen}
options={{
title: "Overview",
headerLeft: () => <Icon.Button name="md-menu" size={25} />,
}}
/>
</Drawer.Navigator>
</NavigationContainer>
</>
);
This is the where most of navigation is in MainTabScreen.js. It contains the Tab Navigation Component that is called in App.js. Each Tab Screen is a Stack: Home, Favorites, Profile, Settings.
MainTabScreen.js
<Tab.Navigator
initialRouteName="Home"
tabBarOptions={{
activeTintColor: "#e91e63",
}}
>
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
tabBarLabel: "Home",
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Favorites"
component={FavoritesStackScreen}
options={{
tabBarLabel: "Favorites",
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="bell" color={color} size={size} />
),
tabBarBadge: 3,
}}
/>
<Tab.Screen
name="Profile"
component={ProfileStackScreen}
options={{
tabBarLabel: "Profile",
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Settings"
component={SettingsStackScreen}
options={{
tabBarLabel: "Settings",
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="cogs" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
export default BottomTabScreen;
// //HOME
const HomeStackScreen = ({ navigation }) => (
<HomeStack.Navigator
initialRouteName="HomeScreen"
headerMode="screen"
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "tomato" },
headerTitleStyle: { fontFamily: "BalsamiqSans_700Bold", fontSize: 30 },
}}
>
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
title: "Home",
headerLeft: () => (
<Icon.Button
name="md-menu"
backgroundColor="tomato"
onPress={() => navigation.openDrawer()}
size={25}
/>
),
}}
/>
<HomeStack.Screen
name="Explore"
component={ExploreScreen}
options={{
title: "Explore",
headerLeft: () => (
<Icon.Button
name="arrow-back-outline"
backgroundColor="tomato"
onPress={() => navigation.goBack()}
size={25}
/>
),
}}
/>
</HomeStack.Navigator>
);
//Favorites
const FavoritesStackScreen = ({ navigation }) => (
<FavoritesStack.Navigator
initialRouteName="FavoritesScreen"
headerMode="screen"
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "tomato" },
headerTitleStyle: { fontFamily: "BalsamiqSans_700Bold", fontSize: 30 },
}}
>
<FavoritesStack.Screen
name="Favorites"
component={FavoritesScreen}
options={{
title: "Favorites",
headerLeft: () => (
<Icon.Button
name="md-menu"
backgroundColor="tomato"
onPress={() => navigation.openDrawer()}
size={25}
/>
),
}}
/>
</FavoritesStack.Navigator>
);
//Profile
const ProfileStackScreen = ({ navigation, route }) => (
<ProfileStack.Navigator
initialRouteName="ProfileScreen"
headerMode="screen"
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "tomato" },
headerTitleStyle: { fontFamily: "BalsamiqSans_700Bold", fontSize: 30 },
}}
>
<ProfileStack.Screen
name="Profile"
component={ProfileScreen}
options={{
title: "Profile",
headerLeft: () => (
<Icon.Button
name="md-menu"
backgroundColor="tomato"
onPress={() => navigation.openDrawer()}
size={25}
/>
),
}}
/>
</ProfileStack.Navigator>
);
//SETTINGS
const SettingsStackScreen = ({ navigation }) => (
<SettingsStack.Navigator
initialRouteName="HomeScreen"
headerMode="screen"
screenOptions={{
headerTintColor: "white",
headerStyle: { backgroundColor: "tomato" },
headerTitleStyle: { fontFamily: "BalsamiqSans_700Bold", fontSize: 30 },
}}
>
<SettingsStack.Screen
name="Settings"
component={Settings}
options={{
title: "Settings",
}}
/>
</SettingsStack.Navigator>
);
I am trying to get HomeScreen to send data via navigation.navigate to ProfileScreen. I used a modal to create this form
HomeScreen.js
<Modal visible={modalOpen} animationType="slide">
<View style={StyleSheet.modalContent}>
<MaterialIcons
name="close"
size={24}
onPress={() => setModal(false)}
/>
<ImageBackground
style={styles.modalTop}
source={require("../img/modalTop.jpg")}
>
<Text style={styles.modalTopText}>Create.</Text>
<Text style={styles.modalTopText}>Share.</Text>
</ImageBackground>
{/*Button to submit and send data to ProfileScreen*/}
<MaterialIcons
name="add"
size={24}
onPress={() => {
setI((prev) => prev + 1);
navigation.navigate("Profile", recipe);
}}
/>
{/*Name of recipe input */}
<TextInput
value={recipe.name}
onChangeText={(e) => handleChange(e, "name")}
placeholder="Put name of Meal"
/>
{/*Time of recipe input */}
<TextInput
onChangeText={(e) => handleChange(e, "time")}
placeholder="Give estimate how long"
/>
{/*Steps of recipe input */}
<TextInput
value={recipe.steps}
onChangeText={(e) => handleChange(e, "steps")}
placeholder="The steps"
/>
{/*Image of recipe input */}
<TextInput
value={recipe.image}
onChangeText={(e) => handleChange(e, "steps")}
placeholder="url of image"
/>
</View>
</Modal>
I am using a Flatlist in ProfileScreen.js to list the data from HomeScreen.js.
I am also using useEffect() to listen submission of this data.
ProfileScreen.js
const [followers, setFollower] = useState(0);
const [following, setFollowing] = useState(0);
// Our list that receives the data
const [recipeList, setRecipeList] = useState([]);
const [params, setParams] = useState();
useEffect(() => {
if (route.params !== undefined) {
setRecipeList((prev) => [...prev, route.params]);
}
}, [route.params]);
//render each MyRecipe
const _renderItem = ({ item }) => {
return (
<View style={styles.recipeContent}>
<Text style={styles.recipeContentName}>{item.name}</Text>
<View style={styles.ImageContainer}>
<Avatar.Image style={styles.recipeImage} size={80}></Avatar.Image>
</View>
<Text style={styles.recipeContentTime}>{item.time} mins</Text>
{(() => {
let a = item.steps;
let res = [];
a.forEach((step) => {
res.push(<Text style={styles.recipeContentStep}>{step}</Text>);
});
return res;
})()}
</View>
);
};
ProfileScreen.js FlatList
<View style={styles.myRecipesBody}>
<FlatList
keyExtractor={(item) => item.key}
data={recipeList}
renderItem={_renderItem}
/>
</View>
I'm wondering if this issue is because of the nature of my navigation architecture, or am I listening to route.params incorrectly? Thanks!
GitHub repo: https://github.com/rrzhang139/myRNapp.git

Categories

Resources