Is is possible to use navigation.toggleDrawer() in navigation options - react-native

In my navigation file , when I want to toggle drawer , get the following error :
TypeError: navigation.openDrawer is not a function.(In
'navigation.openDrawer()', 'navigation.openDrawer' is undefined)
This is my drawer:
const DrawerNavigator = () => {
return (
<Drawer.Navigator
initialRouteName="MYSHIFT"
>
<Drawer.Screen name="MYSHIFT" component={TopTabNavigator} />
</Drawer.Navigator>
)
}
And this is my container navigation :
const CareworkerNavigation = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }} />
<Stack.Screen
name="Main"
options={({ navigation }) => {
return {
headerLeft: () => <Button title="LEFT BUTTON" onPress={() => {
navigation.toggleDrawer(); // <--- this line throws an error
}} />
}
}}
component={DrawerNavigator} />
</Stack.Navigator>
</NavigationContainer>
)
}
export default CareworkerNavigation
Why I can not use navigation.toggleDrawer() in navigation options?
Is is possible to remove this problem ?

If you check the React Navigation docs, "You will need to make the drawer navigator the parent of any navigator where the drawer should be rendered on top of its UI."
React Navigation docs reference
To answer your question : Yes , it is possible.
And here you have a working example:
import React from 'react'
import { Button, View } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createDrawerNavigator } from '#react-navigation/drawer'
import { createStackNavigator } from '#react-navigation/stack'
const Feed = () => <View />
const Notifications = () => <View />
const Profile = () => <View />
const FeedStack = createStackNavigator()
const Home = ({ navigation }) => (
<FeedStack.Navigator>
<FeedStack.Screen
name="Feed"
component={Feed}
options={props => {
const { toggleDrawer } = props.navigation // <-- drawer's navigation (not from stack)
return {
headerLeft: () => <Button title="LEFT BUTTON" onPress={toggleDrawer} />
}
}}
/>
</FeedStack.Navigator>
)
const Drawer = createDrawerNavigator()
export default props => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Feed">
<Drawer.Screen
name="Feed"
component={Home}
options={{ drawerLabel: 'Home' }}
/>
<Drawer.Screen
name="Notifications"
component={Notifications}
options={{ drawerLabel: 'Updates' }}
/>
<Drawer.Screen
name="Profile"
component={Profile}
options={{ drawerLabel: 'Profile' }}
/>
</Drawer.Navigator>
</NavigationContainer>
)
}

While constructing navigation at options, you refer to the navigation of the stack, what cant perform draw actions, try to construct it on header itself
<Stack.Screen
name="Main"
options={() => {
return {
headerLeft: (navigation) => <Button title="LEFT BUTTON" onPress={() => {
navigation.toggleDrawer(); // <--- this line throws an error
}} />
}
}}
component={DrawerNavigator} />
https://github.com/react-navigation/react-navigation/issues/55

Related

Toggling nested drawer

I have this combineNavigator component
const CombineNavigation = () => {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator>
<Drawer.Screen
key="general"
name="Home"
component={MainNavigator}
/>
<Drawer.Screen
key="cit"
name="quotes"
/>
<Drawer.Screen
key="cont"
name="Contact"
/>
</Drawer.Navigator>
);
};
In MainNavigator I have this
I have this
const MainNavigator = () => {
return (
<Stack.Navigator
<Stack.Screen
name="Français"
component={SFrench}
options={({navigation, route}) => ({
headerRight: () => {
return (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<CustomItem
iconName="menu"
onPress={() =>
navigation.dispatch(DrawerActions.toggleDrawer())
}
/>
</HeaderButtons>
);
},
})}
/>
</Stack.Navigator>
and the SFrench is also a drawer. However when I click on the headerRight of it opens the Combine navigation drawer instead of SFrench drawer. How can I fix that?

Expo Material Bottom Tabs Navigator doesn't work -> showing default BottomNavigation from React-Native-Paper

I've been trying to create a normal material bottom tabs navigator and it just doesnt want to work. I also tried another identical code I had and there it works like it should, but with this code the Material bottom Tabs Navigator shows the BottomNavigation from React-Native-Paper. Is there any help?Anything i have to change?
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import AuthScreen from './screens/AuthScreen';
import HomeScreen from './screens/HomeScreen';
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { userAuthStateListener } from './redux/actions/auth';
const Stack = createNativeStackNavigator()
export default function Main() {
const currenUserObject = useSelector(state => state.auth) // access data from redux from here
const dispatch = useDispatch()
useEffect(() => {
dispatch(userAuthStateListener());
}, []);
if (currenUserObject == null) {
console.log("nothing in user obj")
} else {
console.log("this prints" + { currenUserObject })
}
return (
<NavigationContainer>
<Stack.Navigator>
{currenUserObject.currentUser == null ?
<Stack.Screen name='AuthScreen' component={AuthScreen} options={{ headerShown: false }} />
:
<>
<Stack.Screen name='hb' component={HomeScreen} options={{ headerShown: false }} />
</>
}
</Stack.Navigator>
</NavigationContainer>
)
}
And the HomeScreen should have the material bottom tabs navigator.
import { View, Text, StyleSheet, SafeAreaView } from 'react-native'
import React from 'react'
import { Feather } from '#expo/vector-icons'
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
const Tab = createMaterialBottomTabNavigator();
const Test = () => {
return (
<View style={{backgroundColor:"blue"}}>
<Text>Test</Text>
</View>
)
}
//options={{ tabBarIcon: ({ color }) => (<Feather name="home" size={24} color={color} />)}}
//barStyle={{ backgroundColor: "black" }}
export default function HomeScreen() {
return (
<Tab.Navigator barStyle={{ backgroundColor: 'black' }} activeColor="white" shifting={true}>
<Tab.Screen name="Home" component={Test} />
<Tab.Screen name="Search" component={Test} options={{ tabBarColor:"white",tabBarBadge:false, tabBarIcon: ({ color }) => (<Feather name="search" size={24} color={color} />) }} />
<Tab.Screen name="Post" component={Test} options={{ tabBarIcon: ({ color }) => (<Feather name="plus-square" size={24} color={color} />) }} />
<Tab.Screen name="Chat" component={Test} options={{ tabBarIcon: ({ color }) => (<Feather name="message-square" size={24} color={color} />) }} />
<Tab.Screen name="Me" component={Test} options={{ tabBarIcon: ({ color }) => (<Feather name="user" size={24} color={color} />) }} />
</Tab.Navigator>
)
}
But it doesnt show the right material-bottom-tabs-navigator.
It shows this:
Image of wrong navigator
Show right material-bottom-tabs-navigator but it actually shows the bottomnavigation from react-native-paper

Navigate between two stack Navigators after login in react native

This is my first stack
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Home" component={MainScreen} />
<Stack.Screen name="Schools" component={SchoolsScreen} />
<Stack.Screen name="Setting" component={SettingScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Saved" component={SavedData} />
<Stack.Screen name="Profile2" component={Profile2} />
<Stack.Screen name="SchoolDetails" component={SchoolDetailsScreen} />
<Stack.Screen name="Bottom" component={BottomTab} />
</Stack.Navigator>
</NavigationContainer>
This is my second stack
<NavigationContainer>
<Stack.Navigator
initialRouteName="Login"
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Login" component={AuthLogin} />
<Stack.Screen name="Register" component={AuthRegister} />
<Stack.Screen name="Forget" component={ForgetPassword} />
</Stack.Navigator>
</NavigationContainer>
THis is my app.js file
const [auth, setAuth] = useState(false);
useEffect(() => {
(async () => {
const value = await AsyncStorage.getItem("isLoggedin");
console.log(value);
setAuth(value);
})();
}, []);
return (
<SafeAreaView style={{ flex: 1 }}>
<NativeBaseProvider config={config}>
{auth == "true" ? <InsideStack /> : <OutsideStack />}
</NativeBaseProvider>
</SafeAreaView>
);
}
I want to navigate to home screen from login screen , after function call
// navigation.push("Home");
const storeData = async (value) => {
try {
await AsyncStorage.setItem("isLoggedin", JSON.stringify(true));
} catch (e) {
// saving error
}
};
storeData();
navigation.push("Home");
}}
But i got error:
Do you have a screen named 'Home'?
this is the simple code for this. you have to use redux or context api for gloal state management. here is a min example ;
import {NavigationContainer} from '#react-navigation/native';
import React from 'react';
import {useDispatch, useSelector} from 'react-redux';
import {GetUserContacts} from '../logic/getcontact';
import {setContacts} from '../store/actions/ContactActions';
import AuthNavigation from './AuthNavigation';
import RootNavigation from './RootNavigation';
const AppContainer = () => {
const {is_logged_in} = useSelector(state => state.persistedReducer);
const dispatch = useDispatch();
if (is_logged_in) {
GetUserContacts('PK').then(data => {
dispatch(setContacts(data));
});
}
return (
<NavigationContainer>
{is_logged_in ? <RootNavigation /> : <AuthNavigation />}
</NavigationContainer>
);
};
export default AppContainer;
after user logged in you have to make that is_logged_in true. so the navigator changes itself. you will have to persist this so when application restart the user dont need to login again

Pop animation in React navigation

I'm using cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS for animation transition, the problem is animation for pop must be reverse of pushing but not the animation for push and pop is the same and screen transition is in the same way.
How can I change animation for pop so, transition animation is reverse of poping??
I try using it in stack that contains topbar but not works:
<Stack.Navigator
screenOptions={{
...TransitionPresets.SlideFromRightIOS,
}}
mode="card"
headerMode="screen"
>
<Stack.Screen
name="HOME"
component={HomeStack}
options={{
...TransitionPresets.SlideFromRightIOS,
}}
/>
</Stack.Navigator>
const Tab = createMaterialTopTabNavigator();
export default function HomeStack({
navigation,
route,
}: {
navigation: StackNavigationProp<any>;
route: any;
}) {
React.useLayoutEffect(() => {
navigation.setOptions({
headerShown: false,
});
}, [navigation, route]);
useFocusEffect(
React.useCallback(() => {
const onBackPress = () => {
BackHandler.exitApp();
return true;
};
BackHandler.addEventListener("hardwareBackPress", onBackPress);
return () => BackHandler.removeEventListener("hardwareBackPress", onBackPress);
}, []),
);
return (
<Tab.Navigator tabBar={props => <CentralTab {...props} />} tabBarPosition="bottom" lazy>
<Tab.Screen name="GROUPS" component={GroupsScreen} />
<Tab.Screen name="FEED" component={FeedStack} />
<Tab.Screen name="NEW" component={NewStack} />
</Tab.Navigator>
);
}
A way to achieve a Right to Left animation on navigation (and Left to Right when going back) is using the TransitionPresets.SlideFromRightIOS:
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator, TransitionPresets } from '#react-navigation/stack';
<NavigationContainer>
<MainStack.Navigator>
<MainStack.Screen name="ScreenA" component={ScreenA} />
<MainStack.Screen
name="ScreenB"
component={ScreenB}
options={{ ...TransitionPresets.SlideFromRightIOS }}
/>
</MainStack.Navigator>
</NavigationContainer>
You can see it working in this Snack. Works both on iOS and Android.

Using header buttons to navigate to another screen using react-navigaton

I have created a stack navigator with a header button which will be used to navigate to another screen, however I get this error when I try to goto another screen
TypeError: undefined is not an object (evaluating 'navigation.navigate')
And when I console.log(navigation) its undefined. But however when I create a button within a component & navigate to another screen it works. Its only the header buttons that are give me issues.
import {createStackNavigator} from '#react-navigation/stack';
import TabNav from './TabNavBar';
import TestingScreen from '../components/TestingScreen';
const Stack = createStackNavigator();
const NavTest = ({navigation}) => {
navigation.navigate('testingScreen');
};
const StackNavigatorContainer = () => {
return (
<Stack.Navigator>
<Stack.Screen
name={'tabNavigator'}
component={TabNav}
options={{
headerLeft: () => (
<Button title={'go to testing screen'} onPress={NavTest} />
),
}}
/>
<Stack.Screen name={'testingScreen'} component={PostInvoice} />
</Stack.Navigator>
);
};
export default StackNavigatorContainer;
I've also tried...
<Stack.Screen
name={'tabNavigator'}
component={TabNav}
options={{
headerLeft: ({navigation}) => (
<Button title={'go to testing screen'} onPress={() => navigation.navigate('testingScreen)} />
),
}}
/>
And
<Stack.Screen
name={'tabNavigator'}
component={TabNav}
options={{
headerLeft: () => (
<Button title={'go to testing screen'} onPress={({navigation}) => navigation.navigate('testingScreen)} />
),
}}
/>
``
To improve your understanding about my answer, I want to share my code that working well.
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const AppStack = createStackNavigator();
<NavigationContainer>
<AppStack.Navigator>
<AppStack.Screen name="Home" component={Home}
options={({ navigation }) => {
return {
headerTitleAlign: 'center',
headerMode: 'screen',
headerRight: () => (
<Button
onPress={() =>
navigation.navigate('Options')}
title="Crete Group"
color="#00f"
/>
),
}
}}
/>
<AppStack.Screen name="Options" component{Groupoptions} />
</AppStack.Navigator>
</NavigationContainer>
I hope this code help you surely.