React Naitve Navigation: How to show a modal from drawer? - reactjs

Is there a way to show a modal from drawer in React Native?
There was a similar question and I changed my code following the answer.
My current code is like this.
MyRootStackNavigator.tsx
const Stack = createStackNavigator<RootStackParamList>();
const MyRootStackNavigator = () => {
return (
<Stack.Navigator mode="modal">
<Stack.Screen
name="Main"
component={MyDrawerNavigator}
options={{ headerShown: false }}
/>
<Stack.Screen
name="MyModal"
component={MyModal}
/>
</Stack.Navigator>
);
};
MyDrawerNavigation.tsx
const Drawer = createDrawerNavigator();
const MyDrawerNavigator = () => {
return (
<Drawer.Navigator>
<Drawer.Screen
name="Home"
component={MyStackNavigator}
/>
<Drawer.Screen
name="About this app"
component={About}
/>
</Drawer.Navigator>
);
}
But for this code the section to show a modal doesn't appear on drawer. Only Home and About this app sections appear on drawer. How can I set the section to show a modal on drawer?

You can use a CustomDrawerContent which has a modal inside and use a button to open the Modal
function CustomDrawerContent(props) {
const [modalVisible, setModalVisible] = useState(false);
return (
<DrawerContentScrollView {...props}>
<Modal
style={{ flxe: 1, backgroundColor: 'red' }}
visible={modalVisible}
onRequestClose={() => setModalVisible(false)}>
<Text>Modal Content Here</Text>
<Button title="Close" onPress={() => setModalVisible(false)} />
</Modal>
<DrawerItemList {...props} />
<DrawerItem
label="Open Modal"
onPress={() => {
setModalVisible(true);
}}
/>
</DrawerContentScrollView>
);
}
And the DrawerNavigator should be setup like this
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}>
You can refer the docs here
https://reactnavigation.org/docs/drawer-navigator/#providing-a-custom-drawercontent
If you want to continue with the code that you have put in the question, you can do like below to navigate to the about screen (Instead of having the modal inside the content)
<DrawerItem
label="Open Screen"
onPress={() => {
props.navigation.navigate('About')
}}
/>

Related

The action 'NAVIGATE' with payload {"name":"RestaurantDetail"} was not handled by any navigator. Do you have a screen named 'RestaurantDetail'?

I could not fix this bug. It says RestaurantDetail was not handled by any navigator and asks me if I do you have a screen named RestaurantDetail? The idea is to get a restaurant detail card from the bottom of the app. Any help will be appreciated
export const RestaurantsScreen = ({navigation}) => {
const {isLoading, restaurants} = useContext(RestaurantContext);
return (
<SafeArea>
{isLoading && (
<LoadingContainer>
<Loading
size={50}
style={{marginLeft: -25}}
animating={true}
color={Colors.blue300}
/>
</LoadingContainer>
)
}
<Search />
<RestaurantList
data={restaurants}
renderItem={({item}) => {
return(
<Pressable onPress={() => navigation.navigate("RestaurantDetail")}>
<Spacer position="bottom" size="large">
<RestaurantInfoCard restaurant={item} />
</Spacer>
</Pressable>
)}
}
keyExtractor={(item) => item.name}
/>
</SafeArea>
)
};
const RestaurantStack = createStackNavigator();
export const RestaurantsNavigator = () => {
return (
<RestaurantStack.Navigator headerMode="none">
<RestaurantStack.Screen
name="Restaurants"
component={RestaurantsScreen}
/>
<RestaurantStack.Screen
name="RestaurantDetail"
component={() => <Text>Restaurant Detail</Text>}
/>
</RestaurantStack.Navigator>
);
};

How can I create dynamic routes/ screens with React Native?

I want to create dynamic routes similar to the way you can with react-router using the slash colon as so:
<Route exact path="/user/:_id" component={UserPage} />
How does this work with react native if I want to open a page specif to a link?
const Item = ({ title }) => (
<View style={styles.item}>
<Button
onPress={() => {
alert(`You tapped ${title}`);
}}
title={title}
>
<Text style={styles.title}>{title}</Text>
</Button>
</View>
);
const MainPage = () => (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
/>
</SafeAreaView>
);
export default MainPage;
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="MainPage" component={MainPage} />
<Stack.Screen name="MediaScreen" component={MediaScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
I want the Item onPress to go to its own page/screen
As for as I know react native navigation doesnt allow url params, you have to pass parameters when you call the navigate function.
const Item = ({ title, navigation }) => (
<View style={styles.item}>
<Button
onPress={() => {
alert(`You tapped ${title}`);
navigation.navigate('Details', { _id })
}}
title={title}
>
<Text style={styles.title}>{title}</Text>
</Button>
</View>
);
const MainPage = ({ navigation }) => (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} navigation={navigation}/>}
renderSectionHeader={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
/>
</SafeAreaView>
);
export default MainPage;
Then in Details it will have a route parameter which you can get _id from route.params._id
const Details = ({ navigation, route }) => {
const [_id] = useState(route.params._id);
return (
<></>
)
};
With react-navigation you can pass parameters in two ways:
1 - Pass params to a route by putting them in an object as a second parameter to the navigation.navigate function: navigation.navigate('RouteName', { /* params go here */ })
2 - Read the params in your screen component: route.params.
Full documentation https://reactnavigation.org/docs/params

How to render the header again in react navigation when user add something

Here
Let me show you the photo.
What I want to do is I want to add number as badge beside the shopping cart.
But the problem is that the navigation component does not re-render even when I change the value from another component.
here the code for header navigator
const createMyStackNavigator = (name, screen, whatStack) => ({navigation}) => {
whatStack = createStackNavigator();
return (
<whatStack.Navigator
screenOptions={{
headerStyle: {backgroundColor: `${headerColor}`},
headerTintColor: '#fff',
}}>
<whatStack.Screen
name={name}
component={screen}
options={{
title: name,
headerLeft: () => (
<Icon2.Button
name="navicon"
size={25}
backgroundColor={headerColor}
onPress={() => {
navigation.openDrawer();
}}></Icon2.Button>
),
headerRight: () => (
<Icon2.Button
name="shopping-bag"
size={25}
backgroundColor={headerColor}
onPress={() => {
navigation.openDrawer();
}}>
<Text style={{color: 'white'}}>{productInCart}</Text>
</Icon2.Button>
),
}}
/>
</whatStack.Navigator>
);
};
Here is how it creating the navigator
const DrawerNavigator = ({navigation}) => {
const isFocused = useIsFocused();
const cartList = useSelector((state) => state.productReducer.cartList);
productInCart = cartList.OrderDTO?.OrderLines.length
return (
<Drawer.Navigator drawerContent={(props) => <DrawerContent {...props} />}>
<Drawer.Screen
name="ProductScreen"
component={ProductScreenStackScreen}
/>
</Drawer.Navigator>
);
};
As you can see {productinCart} should be updated when its value is updated in other component.
But It's does not. Can you guys suggest some ideas? So that whenever user click certain button
The header will renader again

Why my does drawer navigator screen has no header title, using nested (StackNavigator, DrawerNavigator)

I have problem regarding disappeared header title, Currently I used Nested StackNavigator and DrawerNavigator, I have module when the user is logged in they use the drawer navigator else they will back to stack navigator.
Problem: Why does my header title disappeared ?
Here is my App.js
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const UnauthenticatedScreen = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Login"
component={Login}
options=
{{
headerShown: false,
}}
/>
<Stack.Screen
name="Registration"
component={Register}
options={{
headerStyle: {
backgroundColor: '#4ABDFF'
},
headerTitleStyle: {
color: '#fff',
},
headerTintColor:'#fff',
}}
/>
<Stack.Screen
name="Privacy"
component={PrivacyPolicy}
options={{
headerStyle: {
backgroundColor: '#4ABDFF'
},
headerTitleStyle: {
color: '#fff',
},
headerTitle:'Privacy Policy',
headerTintColor:'#fff',
}}
/>
<Stack.Screen
name="RegistrationSuccess"
component={RegistrationSuccess}
options=
{{
headerShown: false,
}}
/>
</Stack.Navigator>
)
}
const AuthenticatedDriverScreen = () => {
return (
<Drawer.Navigator drawerContent={props=><CustomDriverDrawer {...props} />} initialRouteName="DriverDashboard">
<Drawer.Screen
name="DriverDashboard"
component={DriverDashboard}
options={
{
drawerLabel: 'Home',
drawerIcon: ({focused, color, size}) => (
<Icon type="font-awesome" name="home" style={{fontSize:size, color:"black"}} />
),
}
}
/>
</Drawer.Navigator>
)
}
function Navigator() {
const isLogin = true;
return (
<NavigationContainer>
{isLogin ? <AuthenticatedDriverScreen/> : <UnauthenticatedScreen/>}
</NavigationContainer>
)
}
Authenticated User Screen:
Very well appreciated for your help.
First of all, you need to remember that thing React Navigation providing drawer functionality and screen functionality separately.
for connecting two functionality in one you need to bind the screen with a drawer so you can see both things in one go.
that's why first you need to make one screen navigator that contains single/multiple screen(s) so you can bind that navigator with a drawer like the below code.
const BindedScreenComponent = () => {
return (
<Bind.Navigator>
<Bind.Screen
name="Bind"
component={() => <Text>Bind</Text>}
/>
</Bind.Navigator>
)
}
after that, you need to bind that code into the drawer component so the drawer component can render a whole navigator and give you the desire results
<Drawer.Screen
name="DriverDashboard"
component={BindedScreenComponent}
options={
{
drawerLabel: 'Home',
}
}
/>
snake: https://snack.expo.io/#nishargshah/react-navigation-5-boilerplate
My Old Explanation is correct for multiple screens bound in one screen but if you want only one screen with one drawer then you can use headerShown: true in your drawer options so, it will automatically show the header of the drawer.
Here is the example: https://snack.expo.io/#nishargshah/react-navigation-5-drawer

React native navigation button in the header with parameters

There is a button in the header that is suppose to go to detail page and send parameters. The issue I am having is that when the button is clicked nothing happens. Could you help with this.
I am not sure how to insert navigation button in the header and pass parameters to a screen
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerRight: (navigation) => (
<Button
title="Go to Details"
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
),
}}
/>
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
You have to pass the navigation param to the options prop of the screen.
Try something like this:
<Stack.Screen
name="Home"
component={HomeScreen}
options={({navigation}) => ({
headerRight: () => (
<Button
title="Go to Details"
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
),
})
/>

Resources