Access to react stack navigation inside header component - react-native

Inside the SamplePage, I could access navigation via this.props.navigation.
Inside the SampleHeader component, I have a button.
How I can access navigation in onPress action in button, declared inside SampleHeader?
const AppStackNavigator = createStackNavigator({
SamplePage: {
screen: SamplePage,
navigationOptions: {
title: 'title',
headerStyle: styles.headerStyle,
headerTintColor: styles.headerTintColor,
headerTitleStyle: styles.headerTitleStyle,
headerRight: <SampleHeader></SampleHeader>
}
}
...

you can try this:
SamplePage: {
screen: SamplePage,
navigationOptions: ({ navigation }) => ({
....
headerRight: <SampleHeader navigation={navigation}/>
....
})
}

Try the below code and see if its works , you can pass navigation as props to SampleHeader :
const AppStackNavigator = createStackNavigator({
SamplePage: {
screen: SamplePage,
navigationOptions: {
title: 'title',
headerStyle: styles.headerStyle,
headerTintColor: styles.headerTintColor,
headerTitleStyle: styles.headerTitleStyle,
headerRight: <SampleHeader navigation={this.props.navigation}></SampleHeader>
}
}
or you can create your own SampleHeader as that, and when you call it in a page suppose SamplePage you can add like,
class SamplePage extends Component {
render(){
return(
<SampleHeader navigation={this.props.navigation} />
)
}
}
and then after that , you can access on buttonCLick by this.props.navigation.
Hope it helps. feel free for doubts

Related

How can a TabNavigator child screen refer to parent StackNavigator?

i am trying to navigate from child tab navigator to a screen of parent stack navigator. But this.props.navigation.navigate can only navigate to child's navigation props
'
//stack.js
const AppNavigator = createStackNavigator(
{
DetailPage: DetailPage, //Screen A
MainScreen: { . //Screen B
screen: MainScreen,
navigationOptions: {
header: null
}
}
{
initialRouteName: "MainScreen"
}
}
//MainScreen.js
<View style={{ flex: 1 }}>
<TabScreen />
</View>
//TabScreen.js
const TabScreen = createMaterialTopTabNavigator({
Home: {
screen: HomeStack
},
// Videos: { screen: Videos },
Videos: {
screen: Videos
},
Shows: {
screen: AllShows
},
Live: {
screen: Live
}
})'
I want to navigate from (TabNavigator)TabScreen's Home to (StackNavigator)AppNavigator's DetailPage. But OnPress does Nothing. However, it can navigate to different screens of TabNavigator(child navigator).
Please help me how can I navigate from child TabNavigator to Parent StackNavigator
Nope. you cant do something like this. You need to make sure there is only one navigator defined. If not, need to make sure the navigation state is connected so that navigators know each other. I would strongly suggest you use a single root navigation
Refer Common Mistakes in react navigation
Explicitly rendering more than one navigator
Most apps should only ever render one navigator inside of a React component, and this is usually somewhere near the root component of your app. This is a little bit counter-intuitive at first but it's important for the architecture of React Navigation.
You need to define everything in a single place (root). Like follows
import React, { Component } from "react";
import { View, Text } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
import Camera from "./screens/camera";
import Welcome from "./screens/welcome";
import Scanner from "./screens/scanner";
import Cards from ".//screens/cards";
const BottomNavigation = createMaterialBottomTabNavigator(
{
Scan: { screen: Scanner },
Cards: { screen: Cards },
Settings: { screen: Cards }
},
{
initialRouteName: "Scan",
shifting: true
}
);
const AppNavigator = createStackNavigator({
Welcome: {
screen: Welcome,
navigationOptions: { header: null }
},
Camera: {
screen: Camera,
navigationOptions: { header: null }
},
Home: {
screen: BottomNavigation,
navigationOptions: { header: null }
}
});
export default createAppContainer(AppNavigator);
Now i believe you can navigate to different screens as everything is defined on a single navigator.
Could you try this?
//stack.js
const AppNavigator = createStackNavigator(
{
DetailPage: DetailPage, //Screen A
MainScreen: { . //Screen B
screen: MainScreen,
navigationOptions: {
header: null
}
},
TabScreen : {
screen : TabScreen
},
{
initialRouteName: "TabScreen"
}
}
//TabScreen.js
const TabScreen = createMaterialTopTabNavigator({
Home: {
screen: HomeStack
},
// Videos: { screen: Videos },
Videos: {
screen: Videos
},
Shows: {
screen: AllShows
},
Live: {
screen: Live
}
},
{
initialRouteName: "Home"
}
)'
this.props.navigation.dangerouslyGetParent().navigate('routeName', {});
Also, if you are ready to refactor some code you can create a new Screen and create some extra components, you can create a MainTabScreen for each TabNavigation screen, then:-
App.js
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false
}}
>
<Stack.Screen
name="login"
component={LogIn}
options={{title : 'LOG IN', headerShown: true}}
/>
<Stack.Screen
name="client-tabs-main"
component={ClientTabsMain}
/>
... Other Screens ...
</Stack.Navigator>
</NavigationContainer>
ClientsTabMain.jsx
<Tabs.Navigator
activeColor='white'
barStyle={{backgroundColor: colors.primary}}
>
<Tabs.Screen
name="home-tabs"
component={HomeTab}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="home-outline" color={color} size={18} />
),
}}
/>
<Tabs.Screen
name="portfolio-tabs"
component={PortfolioTab}
options={{
tabBarLabel: 'Portfolio',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="clock" color={color} size={18} />
)
}}
/>
... Other Screens ...
</Tabs.Navigator>
PortfolioTabs.jsx
<PortfolioStack.Navigator
screenOptions={{
headerShown: true
}}
>
<PortfolioStack.Screen
name="portfolio"
component={Portfolio}
options={{
title: 'Portfolio'
}}
/>
<PortfolioStack.Screen
name="transaction"
component={Transaction}
/>
</PortfolioStack.Navigator>
And navigate using :-
this.props.navigation.replace('client-tabs-main',{
screen: 'portfolio-tabs',
params: {
screen: 'portfolio'
}
});
createBottomTabNavigator({
HomeTab: {
screen: HomeStack,
navigationOptions: {
title: "Home",
tabBarOnPress: this.handleTabPress
}
},
MessagingTab: {
screen: MessagingStack,
navigationOptions: {
title: "Messaging",
tabBarOnPress: this.handleTabPress
}
}
});
handleTabPress = ({ navigation }) => {
navigation.popToTop();
navigation.navigate(navigation.state.routeName);
}`

React native - onpress doesn't work inside drawer navigation header

I'm trying to add a custom menu icon button inside the navigation header in my react native app. I successfully did that, but the press event doesn't fire as long as the icon is in the header. For example, if I have the icon here:
https://www.dropbox.com/s/xyah9ei43wgt1ut/menu_regular.png?dl=0
The press event doesn't work, but if I have it here (moved it lower):
https://www.dropbox.com/s/54utpr1efb3o0lm/menu_moved.png?dl=0
The event fires ok.
Here's my current setup navigator:
const MainNavigator = createStackNavigator(
{
login: { screen: MainLoginScreen },
signup: { screen: SignupScreen },
profileScreen: { screen: ProfileScreen },
main: {
screen: createDrawerNavigator({
Home: createStackNavigator(
{
map: {
screen: MapScreen,
headerMode: 'screen',
navigationOptions: {
headerVisible: true,
headerTransparent: false,
headerLeft: (
<View style={{ position: 'absolute', left: 10, display: 'flex', zIndex: 11550 }}>
<Icon
raised
name='bars'
type='font-awesome'
color='rgba(255, 255, 255, 0)'
reverseColor='#444'
onPress={() => { console.log("press"); navigation.goBack() }}
reverse
/>
</View>
)
}
},
history: { screen: HistoryScreen },
foundItem: { screen: FoundItemScreen },
}
),
Settings: {
screen: SettingsScreen,
navigationOptions: ({ navigation }) => ({
title: 'Edit Profile',
})
}
}, {
contentComponent: customDrawerComponent,
drawerWidth: width * 0.8
}
)
}
}, {
headerMode: 'screen',
navigationOptions: {
headerTransparent: true,
headerLeftContainerStyle: { paddingLeft: 20 }
}
}
);
The icon from the screenshot is inside headerLeft.
I've also tried various zIndex values, but with no luck.
Thanks in advance!
Edit:
The drawer has the same issue on the first item, press events don't work on the full area of the drawer item when it's over the header:
https://www.dropbox.com/s/krva5cgp7s59d13/drawer_opened.png?dl=0
Try to wrap Icon inside some Touchable Element like TouchableOpacity/TouchableHighlight and then add an onPress prop to that element
You can get the onPress event in navigationOption's header using navigation params like
static navigationOptions = ({ navigation }) => ({
headerLeft: (
<TouchableOpacity onPress={() => navigation.state.params.handleSave()} >
<Image source={ImageSource} />
</TouchableOpacity>
)
})
Then set the navigation params from the componentDidMount like:
componentDidMount() {
this.props.navigation.setParams({ handleSave: this.onSavePress.bind(this)})
}
then can call the method like:
onSavePress() {
// Do Something
}

component render one time when click tab on drawerNavigator in react native

I'm new on react native getting issue on calling component. Whenever click on drawer navigator tab first time component render and API called But when back to the home page and again call that component API not called. I want to recall that function.
Here is my drawer navigator code :
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: Home,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: () => (
<Icon name="home" size={20} color="#0f1f7b" />
)
},
},
PreviousInspection: {
screen: PreviousInspection,
navigationOptions: {
drawerLabel: 'Previous Inspection',
drawerIcon: () => (
<Icon name="file" size={20} color="#0f1f7b" />
)
},
},
Logout: {
screen: Logout,
navigationOptions: {
drawerLabel: 'Logout',
drawerIcon: () => (
<Icon name="sign-out" size={20} color="#0f1f7b" />
)
},
}
},
{
drawerBackgroundColor: "#fff",
contentOptions: {
activeTintColor: '#000',
inactiveTintColor: '#000',
activeBackgroundColor: '#bfc7f3',
itemStyle: {
fontSize: 12,
},
},
});
react-navigation has a withNavigationFocus HOC which provides an isFocused prop to your component. You can use that to determine when a certain screen has become visible.
import { withNavigationFocus } from 'react-navigation';
class YourScreen extends React.Component {
render() {
...
}
componentDidUpdate(prevProps) {
if (this.props.isFocused && !prevProps.isFocused) {
// Screen has now come into focus, call your method here
}
}
}
export default withNavigationFocus(YourScreen)

How to change screen using stackNavigation in React Native?

I have one screen which in header consists button to go to another screen.
I have already model here, but it doesn't work: As shown below I want to change the screen from RecipeList to NewRecipeForm using Button in header
const AppStackNavigator = createStackNavigator({
List: {
screen: RecipesList,
navigationOptions: {
title:'RecipesList',
headerLeft: (
<Button onPress={()=>this.props.navigation.navigate('NewRecipeForm')}>
<Text>+</Text>
</Button>
)
}},
NewRecipeForm: {screen: CreateRecipeForm,
navigationOptions: {title:'Add new recipe'}},
Details: {screen: RecipesDetails, navigationOptions: {title:'RecipeDetails'}},
export default class App extends React.Component {
render() {
return <AppStackNavigator initialRouteName='List' />;
}
}
I hope that you will help me with solution
You may use your stack navigator as like below, you can able to destructure your navigation property while giving your navigationOptions property as well in the createStackNavigator itself
const AppStackNavigator = createStackNavigator({
List: {
screen: RecipesList,
navigationOptions: ({navigation}) => { //destructure the navigation property here
return {
title: 'RecipesList',
headerLeft: (
<Button onPress={() => navigation.navigate('NewRecipeForm')}>
<Text>+</Text>
</Button>
)
}
}
},
NewRecipeForm: {
screen: CreateRecipeForm,
navigationOptions: { title: 'Add new recipe' }
},
Details: { screen: RecipesDetails, navigationOptions: { title: 'RecipeDetails' } }
});
You cannot access the props of your component in headerLeft, but you can directly use the navigation like this :
<Button onPress={()=> navigation.navigate('NewRecipeForm')}>
You can use following code inside your RecipesList Component instead of having it inside createStackNavigator(). See this Snack for full implementation.
static navigationOptions = ({ navigation }) => {
return {
headerTitle: "RecipesList",
headerLeft: (
<Button
onPress={() => navigation.navigate('NewRecipeForm')}
title="+"
/>
),
};
};

How to avoid overriding 'title' of the header in TabNavigator and its children screens? (react-navigation)

I want to set the title of the TabNavigator as 'Stylebook' with a button.
However, the screens which are children of TabNavigator change the 'title'. I think it's overriding the 'title' prop. How can I avoid it?
This is TabNavigator (my TabBar is in the StackNavigator)
export default TabNavigator(
{
Category: {
screen: StylebookCategoryScreen
},
All: {
screen: StylebookAllScreen
}
} ,{
navigationOptions: ({ navigation }) => ({
title: 'Stylebook',
headerRight: (
<Button onPress={() => navigation.navigate('Wardrobe')}
title="Wardrobe"
/>
)
})
});
StylebookAllScreen is almost identical with StylebookCategoryScreen.
class StylebookAllScreen extends Component {
static navigationOptions = {
title:'All'
}
render() {
return (
<View>
<Text>StylebookALLScreen</Text>
<Text>StylebookALLScreen</Text>
</View>
)
}
}
export default StylebookAllScreen;
I can also change whole structure of the navigator, if I can fix this.
Thanks!
You have to put your StylebookAllScreen component into a StackNavigator and then put that into your TabNavigator. Putting it into a StackNavigator allows you to set props like
navigationOptions: ({navigation}) => ({
title: "Stylebook",
}),
With headerLeft or headerRight you can add a Component (such as a Button to the left/right of your headline.
Try something like this:
const StylebookStack = StackNavigator({
StylebookAllScreen: {
screen: Map,
navigationOptions: ({ navigation }) => ({
title: "Stylebook",
headerTitleStyle: {
....
},
}),
},
});
And then put that into your TabNavigator
export default TabNavigator(
{
Category: {
screen: StylebookCategoryScreen
},
All: {
screen: StylebookStack // <--- HERE
}
} ,{
navigationOptions: ({ navigation }) => ({
title: 'Stylebook',
headerRight: (
<Button onPress={() => navigation.navigate('Wardrobe')}
title="Wardrobe"
/>
)
})
});