React-Native-Popup-Menu and Stack Navigator - react-native-popup-menu

ReactNavigation Stack Navigator has the property HeaderRight useful to place the menu button in the header, but has not a context menu.
Is it possible to integrate the React Native Popup Menu in the Stack Navigator?
Thanks in advance.

It is definitely possible to accomplish. In your root App do the following:
import React, { Component } from 'react';
import { MenuContext } from 'react-native-popup-menu';
import MainNavigator from './components/MainNavigator';
export default class App extends Component {
render() {
return (
<MenuContext>
<MainNavigator />
</MenuContext>
);
}
}
Then the way you've implemented your headerRight should work perfectly.

I set the navigationOptions of StackNavigator setting my custom button as RightHeader
static navigationOptions = ({ navigation }) => ({
title: `${navigation.state.params.Name}`,
headerRight: (
<ContextMenuButton
/>)
I would like to know if it is possible to use the React Native Popup Menu, display and use it in combination with the headerRight

I've been wondering about this as well, and found a solution:
Generally, all the Menu parts have to be inside of the Menu tag, so the MenuTrigger as well.
You can style the MenuTrigger but I didn't get it into the top bar with that.
Good news: It's even easier than that, simply place the whole Menu into your navigationOptions like this:
static navigationOptions = ({navigation}) => ({
title: 'Uploaded Videos',
drawerLockMode: 'locked-closed',
headerRight:
<Menu renderer={SlideInMenu} style={{ zIndex: 10 }}>
<MenuTrigger text="open menu"/>
<MenuOptions style={{ flex: 1 }}>
<Text>Menu</Text>
<MenuOption onSelect={() => { console.log("clicked") text="Click me" />
</MenuOptions>
</Menu>
Caveat: navigationOptions are static, so in your menu you can't use functions of the component. But there are ways around that, see for one example this issue at react-native-navigation. Generally, you should probably use redux for that.
Hopefully this still helps you!

Related

Menu Button To Left Of Stack Navigator Back Button, headerBackVisible: true not working

I'm using a stack navigator nested in a drawer navigator for a react native app using react navigation 6. I'm only showing the header for the stack navigator. I want to put a hamburger menu button on the far left of the header, BUT I also want the default stack navigation back button to be present.
I found the setting headerBackVisible in the documentation, but haven't been able to find any examples of anyone using it, so I'm not sure if I'm using it properly. I'm trying to pass it as headerBackVisible: true in my screen options. No matter what I do, if I put anything else in headerLeft, I cannot get the header back button to show.
Anyone have any suggestions or examples on how to put something to the left of the header back button?
Yes, headerBackVisible is not working with headerLeft. As a workaround, you can import default back button (HeaderBackButton) from #react-navigation/stack and return it along with your hamburger component. Something like this:
import { createStackNavigator, HeaderBackButton } from '#react-navigation/stack';
<Stack.Navigator
screenOptions={({ navigation, route }) => ({
headerLeft: (props) => {
return (
<>
<Text>Menu</Text> // Replace with your hamburger component
{props.canGoBack && <HeaderBackButton {...props} />} // THIS IS WHAT YOU NEED
</>
);
},
})}> ....
<Stack.Screen ... />
<Stack.Screen ... />
</Stack.Navigator>
Snack link: https://snack.expo.dev/#rabiarashid/react-navigation---stack-navigator-example
Update (for react-navigation v6):
In v6, HeaderBackButton is moved to elements library i.e.
import { HeaderBackButton } from '#react-navigation/elements';
Ref: https://reactnavigation.org/docs/upgrading-from-5.x/#some-exports-are-now-moved-to-the-element-library

How to navigate to other screen using the headerRight on the navigator code?

The title is very confusing, but the explanation that I will give will be more clear.
I am creating one StackNavigator for my app, and I am defining one icon to be displayed on the header of one of my screens like so:
const navigator= createStackNavigator(
{
Initial: {
screen: Posts,
navigationOptions: {
title: "All Posts",
headerRight: () => {
return (
<TouchableOpacity style={{ padding: 5 }}>
<Feather name={"plus"} size={30} />
</TouchableOpacity>
);
},
},
},
Details: Details,
Create: Create,
},
{
initialRouteName: "Initial",
}
);
const App = createAppContainer(navigator);
export default () => {
return (
<Provider>
<App />
</Provider>
);
};
The problem is that I want to navigate the user to the Create screen when the user presses the icon that I am rendering on the right side of the header, but I do not know how to have access to the navigation.navigate() function that the navigator generates for all the screens. I know that I can define the header on the Posts' screen file, so I have access to the navigation.navigate() function, but I want to know if there is some way to do it on the App.js file.
EDIT
Reading the documentation I saw that the way that I am was creating the navigator is not what the official documentation recommends. I learned to make it like this by one old course, using React Navigation 4.x, and now with React Navigation 6.x I perceived the difference in the creation and changed the way that I was doing it on my app. You can check the documentation for the problem that I was having here
You can prepare your navigation option this way by sending props
options={(props) => ({
headerRight: () => <TouchableOpacity
onPress={()=>props.navigation.navigate('Screen')} style={{ padding: 5 }}>
<Feather name={"plus"} size={30} />
</TouchableOpacity>
})}

Programatically hiding and showing individual tabs in React Native Router Flux Tabbar

I have a tabbar in my app using React Native Router Flux. There are a couple use cases where hiding or showing specific tabs based on the current user would be very helpful. The main ones I have run into are:
AB testing new tabs to specific users
Showing a special admin tab to certain users with certain privileges
The react-native-router-flux library does not support any options to do this from what I can see. How can I achieve this functionality?
The default tabbar component in react-native-router-flux is just the component from the react-navigation-tabs library. You can import this component directly into your code, customize as needed, and then pass it to react-native-router-flux through the tabBarComponent prop (documented here).
I created a new component, which you should be able to copy directly and just change the logic for actually hiding the tabs based on your state:
import React from 'react'
import { BottomTabBar } from 'react-navigation-tabs'
import { View, TouchableWithoutFeedback } from 'react-native'
import { connect } from 'react-redux'
const HiddenView = () => <View style={{ display: 'none' }} />
const TouchableWithoutFeedbackWrapper = ({
onPress,
onLongPress,
testID,
accessibilityLabel,
...props
}) => (
<TouchableWithoutFeedback
onPress={onPress}
onLongPress={onLongPress}
testID={testID}
hitSlop={{
left: 15,
right: 15,
top: 5,
bottom: 5,
}}
accessibilityLabel={accessibilityLabel}
>
<View {...props} />
</TouchableWithoutFeedback>
)
const TabBarComponent = props => (
<BottomTabBar
{...props}
getButtonComponent={({ route }) => {
if (
(route.key === 'newTab' && !props.showNewTab) ||
(route.key === 'oldTab' && props.hideOldTab)
) {
return HiddenView
}
return TouchableWithoutFeedbackWrapper
}}
/>
)
export default connect(
state => ({ /* state that you need */ }),
{},
)(TabBarComponent)
And then simply imported and used that in my Tabs component:
<Tabs
key="main"
tabBarComponent={TabBarComponent} // the component defined above
...
Detailed look at where these things are getting passed to
Looking at the line of the source of react-native-router-flux, it is using createBottomTabNavigator from the react-navigation library, and passing no component if you do not pass a custom tabBarComponent. The createBottomTabNavigator method in react-navigation comes from this line of the library, and is actually defined in react-navigation-tabs. Now, we can here see in react-navigation-tabs that if no tabBarComponent has been passed, it simply uses BottomTabBar, also defined in react-navigation-tabs. This BottomTabBar, in turn, takes a custom tab button renderer through props, called getButtonComponent.

React Navigation (V2 / V3): How to access navigation.state.index in navigationOptions on screen

I'm building a React Native app and for my navigation I use React Navigation (V3). For my UI elements I use React Native Elements.
I have a screen which I reuse in multiple navigators. Sometimes it is at the root of a stack, and sometimes it's pushed on with a stack. I want to programmatically add a headerLeft element to this screen navigationOptions based on its position in the stack, because I either want the default back button to show, or a burger menu icon to show, if the screen is at the root of the stack (because the stack is nested in a drawer).
So I tried the following:
export class ScannerScreen extends Component {
static navigationOptions = ({ navigation }) => ({
headerLeft:
navigation.state.index > 0 ? (
undefined
) : (
<Icon type="ionicon" name="ios-menu" onPress={navigation.toggleDrawer} />
),
title: strings.scannerTitle
});
// ...
The problem is this doesn't work as navigation.state.index is undefined here. How would one do this with React navigation?
Edit:
As per request I added a screenshot of console.log(navigation) (via <Icon />s onPress.)
I found a hacky solution, which is okay but I also dislike it a bit:
const stackConfig: StackNavigatorConfig = {
cardStyle: styles.card,
navigationOptions: {
headerBackTitleStyle: styles.headerBackTitle,
headerStyle: styles.header,
headerTintColor: "black"
}
};
const HomeStack = createStackNavigator(
{ HomeScreen, RestaurantDetailScreen, MenuScreen, ScannerScreen },
{
...stackConfig,
initialRouteName: "HomeScreen",
navigationOptions: ({ navigation }) => ({
headerLeft:
parseFloat(navigation.state.key.slice(-1)) > 1 ? (
undefined
) : (
<Icon
containerStyle={styles.leftIcon}
type="ionicon"
name={getIconName("menu")}
onPress={navigation.toggleDrawer}
/>
),
...stackConfig.navigationOptions
})
}
);
This way it automatically sets it for the whole stack. You can also do this in the respective screen individual navigation options. But this only works, since the automatically assigned key for the screen contains it's index.

Can't display leftComponentIcon in NavigationBar

I add react-native-navigation-bar to my project. I want to display the left icon as a sidebar icon. I try this code but nothing is displayed :
<NavigationBar
title={'New Tech'}
height={80}
titleColor={'#fff'}
leftComponent={<Icon name="rocket"/> }
/>
ps: am installing react-native-vector-icons and import it by :
import Icon from 'react-native-vector-icons/FontAwesome';
Any help isappreciated.
It depends on your Navigation Version, but it is either called left or headerLeft (newer versions is the later):
static navigationOptions = ({ navigation }) => ({
title: `whatever`,
headerLeft: <Button title="" onPress={() => {/*do something*/}} />,
});