navigation.navigate on a button in headerRight of the Stack Navigator - react-native

Firstly, I have the same issue as Button linking in headerRight. But their solution was simply using functional over component. I cannot simply switch to functional code as I need to use componentDidMount, so I really need solution for a component based headerRight navigation usage.
Stack
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Root"
component={BottomTabs}
options={{
headerRight: ({ navigation }) => (
<View>
<Button
onPress={() => navigation.navigate('Profile')}
</Button>
</View>
),
}}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
BottomTabs
const BottomTabs = createBottomTabNavigator();
function MyTabs() {
return (
<BottomTabs.Navigator
...
This will bring an error that navigation is not available there. Okay that's right, as you cannot use navigation directly in the definition of the Stack Navigator.
Even using:
headerRight: () => {
return <ProfileButtonScreen/>
},
did not help as on that component I still not have the navigation available.
This is too less info but is already going in the right direction. And finally this gave me the idea about misusing the BottomTabs for the defining of the headerRight.

Stack
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Root"
component={BottomTabs}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
BottomTabs
const BottomTabs = createBottomTabNavigator();
function MyTabs({ navigation, route }) {
navigation.setOptions({
headerRight: () => (
<View>
<Button
onPress={() => navigation.navigate('Profile')}
title="To Profile"
>
</Button>
</View>
),
});
return (
<BottomTabs.Navigator
...
This will now let you have a clickable button on stack navigation header.

Related

How to handle authentication on multiple navigators (react-navigation) in React Native?

Here is my tab navigator present in MainNavigator.js,
const MainNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen
name={'Home'}
component={Home} />
<Tab.Screen
name={'About'}
component={About} />
<Tab.Screen
name={'Profile'}
component={Profile} />
</Tab.Navigator>
)
}
I have an AuthNavigator.js which includes a stack navigator,
const AuthNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name={'Login'} component={Login} />
<Stack.Screen name={'Signup'} component={Signup} />
</Stack.Navigator>
}
So, I have a logout button on my Profile Screen in Tab Navigator. I want to Navigate to Login Screen in AuthNavigator with the onPress event. Here is how I tried this,
const Profile = ({navigation}) => {
const logoutHandler = () => {
navigation.navigate('Login');
}
<SafeAreaView>
<TouchableOpacity onPress={logoutHandler}>
<Text>Logout</Text>
</TouchableOpacity>
</SafeAreaView>
}
However, this is not working. As a beginner to React Native I have no idea how to link this Login route into a Stack screen. Really appreciate it if somebody could save my day. Thankyou so much.
Manage 1 state globally (using redux or some other state management tool) and that is isAuthenticated.
Then in your App.js or where ever you have defined your root navigator do the changes likewise : -
<NavigationContainer>
{ isAuthenticated ? <AuthRoutes /> : <UnAuthRoute />
</NavigationContainer>
On login and logout you'll have to update this isAuthenticated state and then routes will be taken care as per the state

React Native navigation 6 (Expo) - how can I toggle the drawer tab from the header of my Tabs navigation?

Hi I have react native (using expo) navigation 6. I am trying to have Tabs (Bottom) navigation and drawer navigation. I want to have the drawer nav hamburger menu inside the header. As far as I can see its being done having the following
headerLeft: (props) => {
return <Button
title="yes"
onPress={() => navigation.toggleDrawer() } />
}
either inside screenOptions or options (of the Tabs navigation). I kept it in screenOptions as I want it to be visible on all screens. However whatever I tried so far I am always getting an err saying either
undefined is not an object (wenn I pass in an object to screenOption (please see full code below)
or
navigation.ToggleDrawer is not a function - when I pass a function to screenOptions (please see full code below). I cannot find any solution or understand what I am doing wrong. Any help would be great!
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Test" component={Test} />
<Drawer.Screen name="s" component={SearchScreen} />
</Drawer.Navigator>
)
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
screenOptions={({ navigation }) => ({ //here I get "undefined is not an object"
headerLeft: (props) => {
return <Button
title="yes"
onPress={() => navigation.toggleDrawer() } />
}
})}
/*screenOptions={{ // here I would get "navigation.ToggleDrawer is not a function"
}}*/
>
<Tab.Screen name="Home" component={HomeScreen}/>
<Tab.Screen name="Tab1" component={Tab1} />
<Tab.Screen name="Tab2" component={Tab2} />
</Tab.Navigator>
);
}
const Navigator = () => {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
)
}
export default Navigator;

React Navigation Bottom Tabs Navigator plus Modal Screen

I have the following code to create a Tab using React Native Navigation v6.x:
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
The HomeScreen has a button which should call a Modal Screen.
My question is: How would I add this modal screen in my Navigator to call it from HomeScreen and how would be this call code?
Thanks!
You don't need to include the modal in the navigator to open it from the homepage.
You could do something like this:
const HomeScreen = () => {
const [modalVisible, setModalVisible] = useState(false);
function _myModal() {
return(
<Modal
animationType="slide"
visible={modalVisible}
onRequestClose={() => {setModalVisible(false)}}
>
<Text>Hello, I am a modal!</Text>
</Modal>
)
}
// your code
return (
<View>
{/*your code*/}
<Pressable
onPress={() => setModalVisible(true)}
>
<Text>Show Modal</Text>
</Pressable>
{_myModal()}
</View>
);
};
The React-Native documentation has an example for class component as well in case you're working with these, and more info that should help you as well.
If you want to open modal screen from your home page then you should create a home screen stack navigator and add two screen in that stack(home and modal screens), and then navigate to that modal by pressing button.
Tab Navigator(RootNavigation MyTabs)
...
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStack} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
Stack Navigator(HomeStack)
cosnt Stack = createStackNavigator();
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="ModalScreen" component={ModalScreen}
options={{ presentation: 'modal' }} />
</Stack.Navigator>
);
}
HomeScreen
export default function HomeScreen({navigation}) {
return (
<View>
<TouchableOpacity onPress={() => navigation.navigate('ModalScreen'}>
<Text>Open ModalScreen</Text>
</TouchableOpacity>
</View>
)
}

I can't hide the tabbar completely, the add button in the middle will show

when I hide the tabbar using tabBarVisible in a specific screen the upper half of the button in the middle will be still visible (above the red line), any ideas how I can hide that also?
I'm using react-navigation v5
const StackNav = (props: any) => {
React.useLayoutEffect(() => {
routes.includes(name)
? navigation.setOptions({tabBarVisible: false;})
: navigation.setOptions({tabBarVisible: true;})
}, [navigation, route]);
return (
<Stack.Navigator>
<Stack.Screen name="home" component={HomeScreen} />
<Stack.Screen name="food" component={FoodScreen} />
<Stack.Screen name="review" component={ReviewScreen} />
</Stack.Navigator>
);
};
so the BottomTab navigation wraps the StackNav that holds all the screens of the App
const BottomTab = () => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
screenOptions={({route}) => ({
tabBarIcon: ({focused}) => {
return <Tab focused={focused} />;
},
})}
>
<Tab.Screen name="profile" component={StackNav} />
<Tab.Screen name="story" component={StackNav} />
</Tab.Navigator>
);
};
React-navigation don't recommend using the tabBarVisible option. To solve your problem, you can use this workflow to hide the tabBar properly.
The principle is simply to take out the screens that don't need the tabBar from the Tab.Navigator by a parent using a Stack.Navigator.
I use this to my own app using the same tabBar UI as you, it works perfectly.

Using StackScreen options from #react-navigation/native

I need to set a button on screen right side header.
import { useNavigation } from '#react-navigation/native';
const App = () => {
const navigation = useNavigation()
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} options={{headerShown: false}} />
<Stack.Screen name="Next" component={NextScreen} options={{
headerRight: () => <Button title="Done" onPress={() => navigation.navigate('Home')}/>,
headerLeft:null
}} />
<Stack.Screen name="SelectPatient" component={SelectPatientScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}
error message shows that Couldn't find a navigation object. Is your component inside ascreen in a navigator?
I also use navigation in HomeScreen and it works. Error occurs in App.js.
how can i put navigation object onPress.
Thanks.
Just an addition to Guruparan's answer, you can't do const navigation = useNavigation() outside of a navigator