Not able to navigate to another tab in BottomTabNavigator - reactjs

I have BottomTabNavigator with 4 tabs I have the structure as in the screenshot below. That is the View below the BottomTabBar which is achieved but, the problem is I am not able to navigate from the Home/search tab to any other tab. Also, I tried with passing navigation in <Appcontainer /> as given below in the code but it is also not working.
I am using react-navigation v3.11.2
Is there any other way to pass navigation prop in <Appcontainer />. Or Any other method so I can able to navigate in BootomTabs.
const Tabs = createBottomTabNavigator(
{
Home: {
screen: Home,
},
Search: {
screen: Search,
},
Add: {
screen: () => null,
navigationOptions: () => ({
tabBarOnPress: async ({ navigation }) => {
navigation.navigate('Upload');
}
}),
},
Profile: {
screen: Profile,
},
},
);
export default class ParentTabs extends React.Component {
render() {
const { navigate } = this.props;
return (
<View>
<AppContainer navigate={navigate} />
<View>
<Text>My Text</Text>
</View>
</View>
);
}
}
const AppContainer = createAppContainer(Tabs);

navigation.navigate('Upload');
You cannot navigate to any random component. Upload should be a route name defined in your tab navigator.
Otherwise, you need to trigger Upload logic inside your Add screen

Related

react-native: How to hide bottom tabbar onPress

I am trying to hide bottomTabbar when I onPress a botton.
In my App.js file I have my ButtomTabNavigator :
const ButtomTabNavigator = createBottomTabNavigator(
{
screenOne: {
screen: RealReviewMain,
navigationOptions: ({ navigation }) => ({
tabBarVisible: true,
})
},
screenTwo: {
screen: RealReviewMain,
//Here I set the tabbarVisible to true
navigationOptions: ({ navigation }) => ({
tabBarVisible: true,
})
},
},
)
From ScreenTwo, I try to hide bottom tabbar using onPress
<TouchableOpacity
onPress={()=> {
this.props.navigation.setParams({ tabBarVisible: false });
}}/>
Is this the right way to do it? nothing happens.
Any advice or comment would be really appreciated! Thanks in advance!
It's possible to hide/show a tabBar based off button press. Using static navigationOptions. An example would be:
static navigationOptions = ({ navigation }) => {
return {tabBarVisible: navigation.state.params.tabBarVisible}
}
This is a simple example, you would need to initialize tabBarVisible since it would be false. A full component could look like:
import React, { Component } from 'react'
import { Text, View, Button } from 'react-native'
class Screen extends Component {
componentDidMount = () => {
this.props.navigation.setParams({ tabBarVisible: true }) //initialize the state
}
static navigationOptions = ({ navigation }) => {
return {tabBarVisible:navigation.state.params && navigation.state.params.tabBarVisible}
}
render() {
return (
<View style={{flex:1}}>
<Button title={"hide"} onPress={() => this.props.navigation.setParams({tabBarVisible:false})}/>
<Button title={"show"} onPress={() => this.props.navigation.setParams({tabBarVisible:true})}/>
</View>
)
}
}
export default Screen
As far as i know, you cannot hide navigation elements once they are rendered in the page.
But, as stated here you can hide navigation elements in specific screens as follows:
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
FeedStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
If you want to hide the navigator in a specific screen you can add an if condition:
if (navigation.state.index > 0 && navigation.state.routes[1].routeName === "<name of the screen>")

How do you navigate to another component that does not receive the props of react navigation?

I'm working with React Native and React Navigation.
I have a component called App.js in which I declare the Drawer Navigation of React-Navigation.
In this I have an option to log out but I can not navigate to another component after removing the AsyncStorage
Does anyone know how to achieve it?
Thank you.
This is my code:
App.js
import { createDrawerNavigator, DrawerItems, NavigationActions } from 'react-navigation';
const customDrawerComponent = (props) => (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView>
<DrawerItems
{...props}
/>
<TouchableOpacity style={styles.button} onPress={this.logOut} >
<Text> Logout </Text>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
);
logOut = () => {
// NOT WORKS
// this.props.navigation.navigate('Login')
//NOT WORKS:
this.myAction();
}
myAction = () => {
const nav = NavigationActions.navigate({
routeName: 'App',
});
return nav;
};
const AppDrawNavigator = createDrawerNavigator(
{
MainComponent: { screen: MainComponent,
navigationOptions: ({navigation}) => ({
drawerLockMode: 'locked-closed'
}) },
Login: { screen: LoginComponent,
navigationOptions: ({navigation}) => ({
drawerLockMode: 'locked-closed'
}) },
User: { screen: UsersComponent }
},
{
contentComponent: customDrawerComponent,
}
);
make this as a class like
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
From your question I understand that either you want to :-
navigate from outside the components
navigate from components which do not have navigation prop.
For this I have tried 2 solutions and both work extremely fine though I based towards the second one.
First Solution
Use withNavigation from react-navigation package. If your components are deeply nested they wont have navigation prop unless u specify them manually or put them in context ;passing navigation prop becomes a real pain. So instead use withNavigation and your component would have navigation prop.
import {withNavigation} from "react-navigation";
const Component = ({navigation}) => {
const onPress = () => {
navigation.navigate(//ROUTE_NAME//)
}
return (
<TouchableOpacity onPress={onPress}>
<Text>Navigate</Text>
</TouchableOpacity>
)
}
export default withNavigation(Component);
Second Solution
Create a helper script and use that.
"use strict";
import React from "react";
import {NavigationActions} from "react-navigation";
let _container; // eslint-disable-line
export const navigation = {
mapProps: (SomeComponent) => {
return class extends React.Component {
static navigationOptions = SomeComponent.navigationOptions; // better use hoist-non-react-statics
render () {
const {navigation: {state: {params}}} = this.props;
return <SomeComponent {...params} {...this.props} />;
}
}
},
setContainer: (container) => {
_container = container;
},
reset: (routeName, params) => {
_container.dispatch(
NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
type: "Navigation/NAVIGATE",
routeName,
params
})
]
})
);
},
goBack: () => {
_container.dispatch(NavigationActions.back());
},
navigate: (routeName, params) => {
_container.dispatch(
NavigationActions.navigate({
type: "Navigation/NAVIGATE",
routeName,
params
})
);
},
navigateDeep: (actions) => {
_container.dispatch(
actions.reduceRight(
(prevAction, action) =>
NavigationActions.navigate({
type: "Navigation/NAVIGATE",
routeName: action.routeName,
params: action.params,
action: prevAction
}),
undefined
)
);
},
getCurrentRoute: () => {
if (!_container || !_container.state.nav) {
return null;
}
return _container.state.nav.routes[_container.state.nav.index] || null;
}
};
In your parent component when you mount the navigation call following:-
"use strict";
import React from "react";
import App from "./routes";
import {navigation} from "utils";
class Setup extends React.Component {
render () {
return (
<App
ref={navigatorRef => {
navigation.setContainer(navigatorRef);
}}
/>
);
}
}
export default App;
Now, in your components you can directly use helpers from this script itself and navigation would be accessibly globally now.
import {navigate} from "utils/navigation";
For more details you can this thread
Your logout function is declared outside of the Navigator. This means you don't have access to the navigation prop there. However, your customDrawerComponent is a screen of your Navigator and it should have access to it.
So you can try something like this (props here are the props passed to the customDrawerComponent):
onPress={()=> {props.navigation.navigate("Login")}}
Plus your App.js seems kind of strange since you're not exporting any component. Have you pasted the whole code of App.js or just parts of it?

react-navigation Customize component produced by TabNavigator

Using react-navigation, in order to achieve this:
I am nesting TabNavigator inside a StackNavigator. Code as follow:
const HomeTabs = TabNavigator(
{
Portfolio: { screen: PortfolioScreen },
Holding: { screen: HoldingScreen }
},
{
//other configs
}
)
const RootNavigator = StackNavigator(
{
Home: { screen: HomeScreen },
},
{
// other configs
}
)
//in App.js render()
return (
<Provider store={Store}>
<View style={{flex: 1}}>
<RootNavigator />
</View>
</Provider>
)
Now, I need a Floating Action Button on both Portfolio and Holding tabs. I do not want to add it twice in both PortfolioScreen and HoldingScreen components.
Is there a way where I can customize the HomeTabs component produced by TabNavigator? Like giving it extra stuffs to render? Is there a HOC API that I am missing? Something like:
class CustomizedHomeTabs extends React.Component {
onFabPress = () => { // do stuffs }
render() {
return (
<FAB onPress={this.onFabPress}></FAB>
)
}
}
export default withTabNavigator(routes, config)(CustomizedHomeTabs) //something like this would be cool!

setParams not working in react-native

I am using react-native with redux. I am trying to update current screen's params so that they can be accessed in a component used in top-bar but parameter is not getting set.
My code is following:
Screen Route:
AlertNameForm: {
screen: AlertNameForm,
navigationOptions: ({navigation}) => CancelAndDone(navigation)
}
Component Screen: In componentDidMount I am setting parameter.
class AlertNameForm {
..........
componentDidMount() {
this.props.navigation.setParams({onDonePress: this.onDonePress})
}
onDonePress: () => {
// want to access this function in top-bar buttons.
}
}
Following is further components:
export const CancelAndDone = (navigation) => ({
headerLeft: <ButtonCancel navigation={navigation} />,
headerRight: <ButtonDone navigation={navigation} />
})
const ButtonDone = withTheme(({navigation, theme: { tertiaryColor } }) => (
<Button color={tertiaryColor} title="Done" onPress={() => {
if (navigation.state.params && navigation.state.params.onDonePress) {
navigation.state.params.onDonePress()
}
else {
navigation.dispatch(NavigationActions.back())
}
}} />
))
But in ButtonDone component I am not able to access function onDonePress
Is there any other way to setParams for current screen in react-native.
You should reference navigation.state.paramsusing this.props since navigation should be passed as a prop to that component.
You can assign the function within the target component as follows:
componentDidMount = () => {
const { navigation } = this.props
navigation.setParams({
onDonePress: () => this.myFunction(),
})
}
myFunction = () => { /*body function*/ }
In your header or footer component call:
navigation.state.params.onDonePress or route.params.onDonePress if you using React Navigation v5.

React Native / React navigation, same level component

I have 2 classes: my default class HomeScreen used for the home page and another class MyList which I use to generate a flatlist on my HomeScreen.
My problem is that I do not succeed in building my navigation function in my MyList class.
I always get the following error: "Can't find variable: navigate".
I took a look at this Calling Navigate on Top Level Component but I really don't know how to implement it in my code.
Here's what I've tried:
class MyList extends React.Component {
_keyExtractor = (item, index) => item.note.id;
_renderItem = ({ item }) => (
<TouchableNativeFeedback
onPress={() => navigate('Note', { noteId: item.note.id })} >
<View>
<Text style={styles.noteElementTitle} >{item.note.title}</Text>
<Text style={styles.noteElementBody} >{item.note.body}</Text>
</View>
</TouchableNativeFeedback>
);
render() {
return (
<FlatList
data={this.props.data}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Notes',
headerStyle: { backgroundColor: 'rgb(255, 187, 0)' },
headerTitleStyle: { color: 'white' },
};
render() {
const { navigate } = this.props.navigation;
return (
<MyList
data={this.state.data}
load={this.state.load}
navig={this.props.navigation}
>
</MyList>
);
}
}
const Project = StackNavigator({
Home: { screen: HomeScreen },
NewNote: { screen: NewNoteScreen },
Note: { screen: NoteScreen }
});
AppRegistry.registerComponent('Project', () => Project);
Thanks for your help.
Because your MyList component is not part of your stack the navigation prop is not available for that.
You have 2 options.
First option you can pass the navigation prop manually to MyList
render() {
const { navigate } = this.props.navigation;
return (
<MyList
data={this.state.data}
load={this.state.load}
navigation={this.props.navigation}
>
</MyList>
);
}
Second option you can use withNavigation.
withNavigation is a Higher Order Component which passes the navigation
prop into a wrapped Component. It's useful when you cannot pass the
navigation prop into the component directly, or don't want to pass it
in case of a deeply nested child.
import { Button } 'react-native';
import { withNavigation } from 'react-navigation';
const MyComponent = ({ to, navigation }) => (
<Button title={`navigate to ${to}`} onPress={() => navigation.navigate(to)} />
);
const MyComponentWithNavigation = withNavigation(MyComponent);

Resources