USING DrawerNavigator AND BottomTabNavigator HOW TO PUT DrawerIcon - reactjs

Im using my main menu with DrawerNavigator.
Inside a screen i use BottomTabNavigator.
I put the DrawerIcon of each screen like this:
....
export default class HomeScreen extends React.Component {
...
static navigationOptions = {
drawerIcon: ({ tintColor }) => (
<Icon name="home" style={{ fontSize: 24, color: tintColor }} />
)
}
...
}
But, in the screen that i use the TabNavigator i dont export a class, y export createBottomNavigator, like so:
class MetasSemanaAnterior extends React.Component {...}
class MetasScreen extends React.Component {...}
export default createBottomTabNavigator({
MetasMain: MetasScreen,
MetasAnterior: MetasSemanaAnterior,
});
I dont know where put my navigationOptions of the DrawerNavigator!
Help Please! TY

Not Sure if this is what you are looking for but you could try this if i am understanding it correctly.
You could refer https://reactnavigation.org/docs/en/navigation-options-resolution.html for things to make sense.
const tabNavigator = createBottomTabNavigator({
MetasMain: MetasScreen,
MetasAnterior: MetasSemanaAnterior,
});
tabNavigator.navigationOptions = () => {
}
export default tabNavigator;

i solved in this way:
in the main screen, where i create my Drawer Navigation, i set the DrawerIcon. So that, the icon appear despite i dont set it in the child Screens
set DrawerIcon where you create the DrawerMenu:
const AppDrawerNavigator = createDrawerNavigator({
ChatBot: {
screen: HomeScreen
},
Profile: {
screen: ProfileScreen
},
METAS: {
screen: MetasScreen,
navigationOptions: {
//here i set the drawerIcon
drawerIcon: ({ tintColor }) => { return (<Icon name="flag" style={{ fontSize: 24 }} />) }
}
}
}

Related

Using React Navigation for a Navigator inside a Screen?

In my react native app, I have a stack navigator as so:
const AppStack = createStackNavigator(
{
Tabs: AppTabs,
Account: AccountScreen,
Profile: ProfileScreen,
Post: PostScreen,
},
);
The ProfileScreen contains some header content and another TabNavigator, in a layout similar to when you click on a channel in Youtube:
const ProfileTabs = createMaterialTopTabNavigator(
{
Home: ProfileHome,
Posts: ProfileMade,
},
);
const ProfileNav = createAppContainer(ProfileTabs);
class ProfileScreen extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
<View>Some header content</View>
<ProfileNav />
</View>
);
}
}
My problem is that I am unable to navigate from inside the ProfileTabs navigator to a screen in the original stacknavigator. E.g. if a user clicks on a post in the ProfileMade screen, I want to navigate them to the PostScreen.
Please can someone tell me what should be changed? Thanks
You can navigate to another stack sending the name of stack on the .navigate() method:
navigation.navigate('StackName', {
screen: 'YourScreenName'
});

React Native - pass props from One screen to another screen (using tab navigator to navigate)

I need to pass data from my HomeScreen to my SecondScreen. There are a ton of examples of how to do this if i'm clicking a button on the HomeScreen to navigate to SecondScreen, but can't find anything showing how to pass to SecondScreen if I'm using a v2 bottom tab navigator to go from HomeScreen to SecondScreen. I've tried screenprops and a couple other methods and spent about 8 hours trying to figure it out but could not get it to work. Any idea how to do this? Please, any hint would be amazing. Here is my code:
MainTabNavigator.js:
const config = Platform.select({
web: { headerMode: 'screen' },
default: {},
});
const HomeStack = createStackNavigator(
{
Home: HomeScreen,
},
config
);
HomeStack.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => (
<MaterialIcons name="home" size={32} />
),
};
HomeStack.path = '';
const SecondStack= createStackNavigator(
{
Second: SecondScreen,
},
config
);
SecondStack.navigationOptions = {
tabBarLabel: 'Second screen stuff',
tabBarIcon: ({ focused }) => (
<MaterialIcons name="SecondScreenIcon" size={32} />
),
};
SecondStack.path = '';
const tabNavigator = createBottomTabNavigator({
HomeStack,
SecondScreen
});
tabNavigator.path = '';
export default tabNavigator;
HomeScreen.js:
class HomeScreen extends Component {
constructor(props){
super(props);
}
componentDidMount(){
this.setState({DataFromHomeScreen: 'my data that Im trying to send to SecondScreen'})
}
//....
SecondScreen.js:
class SecondScreen extends Component {
constructor(props){
super(props);
}
render()
return(
<View>{this.props.DataFromHomeScreen}</View>
)
//....
****Please find THINGS I'VE TRIED below:****
HomeScreen.js: when i do this it receives it at first but then passes null
render(){
return(
<View>
//all of my home screen jsx
<SecondScreen screenProps={{DataFromHomeScreen : 'data im trying to pass'}}/>
</View>
)
}
MaintTabNavigator.js: when i do this it receives it at first but then passes null
HomeStack.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => (
<MaterialIcons name="home" size={32} />
),
};
<HomeStack screenProps={{DataFromHomeScreen:'data im trying to pass'}}/>
HomeStack.path = '';
I've tried like 5 other ways too that I can't even remember at this point. I don't want to have to call my database again in the second screen to get user info. Nobody I know knows react or react native. The React Native documentation at https://reactnavigation.org/docs/en/stack-navigator.html is minimal at best, only showing the below:
const SomeStack = createStackNavigator({
// config
});
<SomeStack
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>
even if you go to the examples in the documentation and search for the word 'screenprop' you will not see any mention of the screen prop feature in either of the examples. All questions that I've seen only address how to pass props on button click which is easy. Is what I'm trying to do possible? I'm sure I'm not the only person using tab navigator who's retrieved data in the homescreen and need to pass it to other screens . Any advice helps. thanks.
ps.
Here is my Sign in class that is calling the Home screen:
class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};
render() {
return (
<View
style={styles.container}
contentContainerStyle={styles.contentContainer}>
<View>
<SocialIcon
title='Continue With Facebook'
button
type='facebook'
iconSize="36"
onPress={this._signInAsync}
/>
</View>
);
}
_signInAsync = async () => {
let redirectUrl = AuthSession.getRedirectUrl();
let result = await AuthSession.startAsync({
authUrl:
`https://www.facebook.com/v2.8/dialog/oauth?response_type=token` +
`&client_id=${FB_APP_ID}` +
`&redirect_uri=${encodeURIComponent(redirectUrl)}`,
});
var token = result.params.access_token
await AsyncStorage.setItem('userToken', token);
await fetch(`https://graph.facebook.com/me?fields=email,name&access_token=${token}`).then((response) => response.json()).then((json) => {
this.props.navigation.navigate('Home',
{
UserName : json.name,
FBID : json.id,
email : json.email
});
}) .catch(() => {
console.log('ERROR GETTING DATA FROM FACEBOOK')
});
};
}
export default SignInScreen;
I think you're calling your database in componentDidMount in your HomeScreen component, (I'm right?) and because another component in the same hierarchy needs the same data, you should considerer wrapping this into a new component and do the call to your data in that father component, then you pass the data to all the children that needs it. This is the react way to do things. The state of HomeScreen should not have the data, your data should live in a parent component in a higher hierarchy and pass the data to children as props.
In this way when you create your tabs you can pass the props as the react native docs suggest:
import { createBottomTabNavigator, BottomTabBar } from 'react-navigation-tabs';
const TabBarComponent = (props) => (<BottomTabBar {...props} />);
const TabScreens = createBottomTabNavigator(
{
tabBarComponent: props =>
<TabBarComponent
{...props}
style={{ borderTopColor: '#605F60' }}
/>,
},
);
Another solution could be to use a global state management with Redux or something similar.
I hope this helps.
Edit:
class Home extends React.Component{
constructor(props){
super(props);
this.state = {data: null}
}
componentDidMount() {
//get your props from navigation (your facebook credentials)
//your call to database
this.setState({data: yourResponseData});
}
render(){
const TabNavigator = createBottomTabNavigator(
{
HomeScreen: props =>
<HomeScreenStack
{...this.state.data}
/>,
SecondStack: props =>
<SecondStack
{...this.state.data}
/>,
},
);
return(
<TabNavigator />
)
}
}
const App = createAppContainer(Home);
export default App;
Use this.props.navigation.navigate.
In your HomeScreen, once you have the data you want to send, then navigate over to SecondScreen like so:
this.props.navigation.navigate('Second', { data: yourData })
To access this in SecondScreen whenever it is navigated to using navigation props, you can use NavigationEvents along with this.props.navigation.getParam.
/* your imports */
import { NavigationEvents } from 'react-navigation';
export default class SecondScreen extends React.Component {
/* your methods and properties */
render() {
<View>
<NavigationEvents
onDidFocus={() => this.setState({ data: this.props.navigation.getParam('data', {}) })}
/>
{ /* your SecondScreen render code */ }
</View>
}
}
Edit: For example, with your SignInScreen implementation, to access the props, use:
const username = this.props.navigation.getParam('UserName', '')
const fbid = this.props.navigation.getParam('FBID', 0)
const email = this.props.navigation.getParam('email', '')
This is the basic approach that I am using:
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const TestComponent = (props) => {
return <Text>{`TestComponent: ${props.name}`}</Text>;
};
const Home = () => {
const Tab = createBottomTabNavigator();
return (
<View style={{flex: 1}}>
<Tab.Navigator>
<Tab.Screen name="Screen 1">
{() => <TestComponent name="test 1" />}
</Tab.Screen>
<Tab.Screen name="Screen 2">
{() => <TestComponent name="test 2" />}
</Tab.Screen>
</Tab.Navigator>
</View>
);
};
Notice that to pass the props to a Screen I am using a child function instead of passing a value to component. The child function can then return the component you want in the syntax you are used to, that has the props available. In this case, the props are the simple name, but you can expand this to handle your state.
I ended up using Redux, it only took me like 100 read throughs and attempts to learn it, but once I learned it it's amazing and simple.

Rendering both drawer and tabbed navigation with react navigation

I'm using React Navigation in my react native app, and I'm looking to render both the drawer navigation and tab navigation components simultaneously.
At first, I tried to render both in the root app component, but that threw an error that appears in their documentation here. I then attempted the solution listed below, which produced the following for me:
const TabNavigator = createBottomTabNavigator({
Settings: {
screen: SettingsScreen
}
});
const AppNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
Products: {
screen: ProductsScreen
},
TabNav: TabNavigator
});
export default class App extends React.Component {
render() {
return <AppNavigator />;
}
}
The tab navigation only shows when I select the TabNav link in the drawer navigation. I want it on every screen. I also don't want the TabNav label to show in the drawer navigation.
Am I missing something in the documentation, or is this the intended functionality?
For the first question, move the TabNav to first in the navigator like this
TabNav: TabNavigator,
Home: {
screen: HomeScreen
},
Products: {
screen: ProductsScreen
}
or else you change the initialRouteName to "TabNav"
For the Second question,
If you want the TabNavigation to show inside the HomeScreen and ProductsScreen you need to include TabNavigation in both
or they need to have a parent TabNavigation which contains those. I can add a sample code if you post what the TabNav contains.
And for the Third question,
You can use contentComponent in DrawerNavigator example like this
contentComponent: props => (
<AppDrawerContent {...props} navigation={props.navigation} />
),
Edited:
If you want TabNavigator to show on each one. I think you should change the way you Structure your navigator.
export default class App extends React.Component {
render() {
return < TabNavigator />;
}
}
const TabNavigator = createBottomTabNavigator({
Drawer: {
screen: AppNavigator
}
});
const AppNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
Products: {
screen: ProductsScreen
}
});
or else if you want TabNavigator inside each screen individually then
const AppNavigator = createDrawerNavigator({
HomeNavigator: {
screen: HomeScreenNavigator
},
Products: {
screen: ProductsScreen
}
});
const HomeScreenNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen
},
Settings: {
screen: SettingsScreen
}
});
export default class App extends React.Component {
render() {
return <AppNavigator />;
}
}
Like wise for Products screen also.
What you have actually done is you included the TabNav as Drawer Screen so it does appear in the Drawer side bar.
Even if this structure doesn't work you need to check on restructuring it. Or you may give a images how you want to show it. May be I could help you with better understanding.

Pass state data between component through navigator

my issue is look so simple but I can't figure is out how to solve it
I have two component that I navigate to them by using StackNavigator,
in one of the component I have state with values, I need to pass the state values to the other component, but as I said I using StackNavigator to go from one component to the other, I trying to figure out how can I do so
my navigator:
const Navigate = StackNavigator(
{
Home: { screen: HomeScreen },
Riddles: { screen: RiddlesScreen },
Introduction: { screen: IntroductionScreen },
About: { screen: AboutScreen },
},
{ headerMode: 'screen' }
);
My homescreen class:
class HomeScreen extends Component {
static navigationOptions = {
header: null
}
render() {
return (
<View>
<Home navigation={this.props.navigation} />
</View>
);
}
}
my riddlescreen class:
class RiddlesScreen extends Component {
static navigationOptions = {
header: null
}
render() {
return (
<View>
<Riddles navigation={this.props.navigation} />
</View>
);
}
}
in the Riddles component (at the RiddleScreen class) I have state with the values that I need to pass to Home component (at HomeScreen class).
what is the best way to achieve this goal?
every help really appreciated! thanks.
You can pass data between screens while navigating. More info here.
Example
<Button onPress={() => {this.props.navigation.navigate('SomeScreen', { some: this.state.someValue})}} />
// and in SomeScreen
console.log(this.props.navigation.state.params.some);

Integrate StackNavigator with TabNavigator

How do I combine StackNavigator and TabNavigator?
My following code works:
index.android.js :
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import { StackNavigator,TabNavigator } from 'react-navigation';
import TestComp1 from './src/components/TestComp1'
import TestComp2 from './src/components/TestComp2'
import TestComp3 from './src/components/TestComp3'
import TestComp4 from './src/components/TestComp4'
import TestComp5 from './src/components/TestComp5'
export default class myApp extends Component {
render() {
return (
<MyApp />
);
}
}
const MyApp = StackNavigator({
TestComp1: {screen:TestComp1},
TestComp2: {screen:TestComp2}
});
const Tabs = TabNavigator({
TestComp3: {screen:TestComp3},
TestComp4: {screen:TestComp4}
TestComp5: {screen:TestComp5}
});
AppRegistry.registerComponent('myApp', () => myApp);
This works only for StackNavigator. I want to keep the existing navigation and integrate TabNavigation. Now in TestComp1 if I do the following:
TestComp1 :
import { StackNavigator, TabNavigator } from 'react-navigation';
import { FooterTabs } from './routes/FooterTabs';
export default class HomePage extends Component {
static navigationOptions = {
header: null
};
render() {
return(
<View style={styles.container}>
<View style={styles.mainContent}>
<Button
onPress={() => this.props.navigation.navigate('TestComp1', {name: 'Lucy'})}
title="NewPage"
/>
<FooterTabs /> //Page shows all StackNavigator screens if I add this
</View>
</View>
)
}
}
And the FooterTabs:
import { StackNavigator, TabNavigator } from 'react-navigation';
import TestComp3 from '../TestComp3';
import TestComp4 from '../TestComp4';
import TestComp5 from '../TestComp5';
export const FooterTabs = TabNavigator({
Tab1: {
screen: TestComp3
},
Tab2: {
screen: TestComp4
},
Tab3: {
screen: TestComp5
},
})
The FooterTabs is shown but TestComp1 and TestComp2 are also shown everything below one another. How do I fix this? Thanks.
UPDATE 1:
UPDATE 2:
const Tabs = TabNavigator({
TestComp3: {screen:TestComp1},
TestComp4: {
screen:TestComp4,
navigationOptions: ({ navigation }) => ({
title: "TestComp4",
tabBarIcon: ({ tintColor }) => <MaterialIcons name="accessibility" size={20}/>
})
}
UPDATE 3
I added another const for DrawerNavigator and configured it like this:
const Drawer = DrawerNavigator({
First:{
screen: DrawerScreen1
},
Second:{
screen: DrawerScreen2
}
},{
initialRouteName:'First',
drawerPosition: 'left'
});
And included in the app:
const MyApp = StackNavigator({
TestComp1: {screen:TestComp1},
TestComp2: {screen:TestComp2},
Tabs: {
screen: Tabs
},
Drawer: {
screen: Drawer
},
}, {
initialRouteName: "Tabs"
});
I'm calling it :
<Button
onPress={() => this.props.navigation.navigate('DrawerOpen')}
title="Show Drawer"
/>
OnPress of this button the DrawerScreen1 is called but as a component, it does not show as a drawer from the left. What am I missing?
You can try this:
const Tabs = TabNavigator({
TestComp3: {screen:TestComp3},
TestComp4: {screen:TestComp4}
TestComp5: {screen:TestComp5}
});
const MyApp = StackNavigator({
TestComp1: {screen:TestComp1},
TestComp2: {screen:TestComp2},
Tabs: {
screen: Tabs
}
}, {
initialRouteName: "Tabs"
});
and remove <FooterTabs /> from TestComp1
Let's see now. What you need is first a StackNavigator then inside one of the screens of the StackNavigator you need a TabNavigator. Right?
The answer to this would be the following:
For your index.android.js:
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import TestComp1 from './src/components/TestComp1'
import TestComp2 from './src/components/TestComp2'
// Don't need to export default here since this is the root component
// that is registered with AppRegistry and we don't need to import it anywhere.
class myApp extends Component {
render() {
return (
<MyApp />
);
}
}
// Notice that these two screens will consist the navigation stack.
// Assume, TestComp1 contains our Tabbed layout.
const MyApp = StackNavigator({
TestComp1: { screen:TestComp1 }, // This screen will have tabs.
TestComp2: { screen:TestComp2 }
});
AppRegistry.registerComponent('myApp', () => myApp);
Let's now move on to your TestComp1, which is the screen that has your tabs.
TestComp1:
// ... all imports here.
// This should be your first tab.
class Home extends Component {
static navigationOptions = {
// Label for your tab. Can also place a tab icon here.
tabBarLabel: 'Home',
};
render() {
return(
<View style={styles.container}>
<View style={styles.mainContent}>
// This will change your tab to 'Profile'.
<Button
onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})}
title="NewPage"
/>
</View>
</View>
)
}
}
// This can be your second tab and so on.
class Profile extends Component {
static navigationOptions = {
// Label for your tab.
tabBarLabel: 'Profile',
};
render() {
return (
<Text>This is the profile Tab.<Text>
);
}
}
export default TabNavigator({
Home: {
screen: Home,
},
Profile: {
screen: Profile,
},
}, {
// This will get the tabs to show their labels/icons at the bottom.
tabBarPosition: 'bottom',
animationEnabled: true,
tabBarOptions: {
activeTintColor: '#e91e63',
},
});
So essentially, your TestComp1 has two components (Home and Profile) inside it which are both parts of TabNavigator so they'll act as tabs. (You don't need to worry about a separate footer component as ReactNavigation places that automatically using your component's navigationOptions) We'll be exporting this TabNavigator instance that we'll use as an import to index.android.js and we'll place this import inside our StackNavigator as a screen of the app.
This way you've incorporated Tabs as well as StackNavigator inside your RN app. Also, tabBarPosition: 'bottom' places your tabs at the bottom.
You also no longer to maintain a separate FooterTabs component as you can see.
Read up the docs if you need more clarity or fine-tuning.
Hope I've helped. :)

Resources