Accessing Context Inside of TabNavigator? React Native - react-native

I currently have a tab navigator nested inside a stack navigator.
I've been trying to adjust my tabnavigator so it's able to leverage the useContext() hook to conditionally display a tab but haven't had any luck.
Here's my navigation.js file:
const TabNavigator = createBottomTabNavigator(
{
...(myInfo
? {
MyInfo: {
screen: MyInfo,
navigationOptions: {
tabBarIcon: ({ focused }) => {
let source;
focused
? (source = require('../assets/MyInfo_Inactive.png'))
: (source = require('../assets/MyInfo_Inactive.png'));
return <Image style={{ marginTop: 30 }} source={source} />;
},
},
},
}
: {}),
Account: {
screen: Account,
navigationOptions: {
tabBarIcon: ({ focused }) => {
let source;
focused
? (source = require('../assets/Account_Inactive.png'))
: (source = require('../assets/Account_Inactive.png'));
return <Image style={{ marginTop: 30 }} source={source} />;
},
},
},
},
{
defaultNavigationOptions: {
tabBarOptions: {
showLabel: false,
},
},
},
);
const MainStackNavigator = createStackNavigator(
{
Tabs: {
screen: TabNavigator,
},
Login: {
screen: Login,
},
},
{
initialRouteName: 'Login',
headerMode: 'none',
},
);
export default MainStackNavigator;
Where 'myInfo' would come from my context.
and my App.js file:
const AppContainer = createAppContainer(MainStackNavigator);
const App: () => React$Node = () => {
return (
<AccountProvider>
<AppContainer />
</AccountProvider>
);
};
export default App;
Any help is super appreciated as I'm new to React Native and have been trying to find an answer that works for quite some time.
Thanks!

Related

How to display tab bar icon in react navigation 4

I want to display bottom tab tar in react-navigation 4, but there is no luck to make it happen, even I use it. Can anyone help me to find the problem with my code or which option should I use?
static navigationOptions = {
title: "Map",
tabBarIcon: ({ tintColor }) => {
return <Icon name="home" size={30} color={tintColor} />;
}
}
in any component screen, it does still not work.
Here is my router
I want to apply the bottom tab icon to homescreen
const MainAuthenticated = createAppContainer(
createBottomTabNavigator(
{
main: {
screen: createBottomTabNavigator({
Marketplace: {
screen: createStackNavigator({
home: {
screen: HomeScreen,
},
profile: { screen: Profile },
business: { screen: MyBusiness },
logout: { screen: Logout },
itemlist: { screen: ItemList },
itemcreate: { screen: ItemCreate },
itemdetail: { screen: ItemDetail },
businesscreate: { screen: BusinessCreate },
businessdetail: { screen: MyBusinessDetail },
}),
},
XOrders: { screen: OrderScreen },
Favorite: { screen: FavoriteScreen },
}),
},
},
{
defaultNavigationOptions: {
tabBarVisible: false,
},
},
),
);
Here is the working code to add the bottom tab bar icon in react-navigation v4
import Ionicons from 'react-native-vector-icons/Ionicons';
import { createAppContainer } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
export default createBottomTabNavigator(
{
Home: HomeScreen,
Settings: SettingsScreen,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline';
// Sometimes we want to add badges to some icons.
// You can check the implementation below.
IconComponent = HomeIconWithBadge;
} else if (routeName === 'Settings') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
// You can return any component that you like here!
return <IconComponent name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
);
If you wanted to use some .png or jpeg or some other image file instead of vector icons just replace this
<IconComponent name={iconName} size={25} color={tintColor} /> // replace this with below
<Image source={require('your image path')} style={{height: 30, width: 30}} />

How do I conditionally render a header in a Stack Navigator for React Native Navigation?

I would like my initial page to NOT contain a header. However, I would like a header to appear on each subsequent page. Right now my current stackNavigator looks like this:
const AppNavigator = createStackNavigator(
{
HomeScreen: HomePage,
SecondPage: SecondPage,
Account: Account,
About: About,
},
{
initialRouteName: 'HomeScreen',
headerMode: 'none',
navigationOptions: {
headerVisible: false,
},
},
);
export default createAppContainer(AppNavigator);
Here is the basic boilerplate for my second page:
const SecondPage: () => React$Node = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<View style={styles.body}>
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>This is the Secondpage</Text>
</View>
</View>
</>
);
};
export default SecondPage;
You have three ways of doing this using navigationOptions:
1) Directly when you define your navigator:
createStackNavigator({
{
HomeScreen: {
screen : HomePage,
navigationOptions: {header : null}
},
SecondPage: SecondPage,
Account: Account,
About: About,
},
{ ... } //your navigationOptions
})
2) Directly inside the screen as said by Shashank Malviya. Only if you aren't using a functional component.
3) Return defaultNavigationOptions as a function and use navigation state:
createStackNavigator({
{ ... }, //your RouteConfigs
{
initialRouteName: 'HomeScreen',
headerMode: 'none',
defaultNavigationOptions : ({navigation}) => navigation.state.routeName === "HomePage" && {header: null}
},
})
Can be written on every component before render
static navigationOptions = ({ navigation }) => {
const { state } = navigation
return {
headerVisible: true // can be true or false
}
}

Use the same custom header in all pages in React Native using AppContainer problems

I'm using react-native with react-navigation, and I'm hitting this issue with my screens not rendering correctly. I'm referencing this link to use the same disappearing header as a wrapper around my AppContainer:
https://medium.com/appandflow/react-native-scrollview-animated-header-10a18cb9469e
The first screen AuthLoadingScreen shows up fine, and then is supposed to navigate to the either of the stack's based on whether the user is verified. But for some reason, nothing shows up after the user is verified or not. I have a console.log upon entering both stacks and they both fire fine, just nothing gets rendered... any ideas are appreciated.
Here are some snippets of code that I have so far:
<- App.js ->
<View style={styles.fill}>
<Animated.ScrollView
style={styles.fill}
scrollEventThrottle={1}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
{ useNativeDriver: true },
)}
>
<-----My AppContainer----->
<AppContainer />
<------------------------->
</Animated.ScrollView>
<Animated.View
pointerEvents="none"
style={[
styles.header,
{ transform: [{ translateY: headerTranslate }] },
]}
>
<Animated.Image
style={[
styles.backgroundImage,
{
opacity: imageOpacity,
transform: [{ translateY: imageTranslate }],
},
]}
source={require('./assets/images/casino/casino-10.jpg')}
/>
</Animated.View>
</View>
<-My App Container consists of->:
import AuthLoadingScreen from '../screens/AuthLoadingScreen';
const AppStack = createStackNavigator({
Home: { screen: HomeScreen },
Settings: { screen: SettingsScreen },
OfferCategories: { screen: OfferCategoriesScreen },
});
const AuthStack = createStackNavigator({
Login: LoginScreen
});
export default createAppContainer({createSwitchNavigator({
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
})});
You can do it with two options: Warp in the AppContainer, or define the header section inside the top level of navigators:
lets start with the first option:
you can do
const AppContainerNavigator = createAppContainer({createSwitchNavigator({
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
})});
export default class AppContainer extends Component {
render() {
return (
<YOUR_HEADER_COMPONENT>
<AppContainerNavigator
ref={nav => {
this.navigator = nav;
}}
/>
</YOUR_HEADER_COMPONENT>
)
}
}
Or the other one is to pass the header component to your navigator while define it something like the following:
let MY_HEADER_COMPONENT = {
headerLeft: () => {
return null;
},
header: () => {
return <YOUR_HEADER_COMPONENT></YOUR_HEADER_COMPONENT>;
},
headerRight: () => {
return null;
}
};
export default createStackNavigator({
AuthLoading:{
screen: AuthLoadingScreen,
navigationOptions: ({
navigation
}) => (MY_HEADER_COMPONENT)},
App:{
screen: AppStack,
navigationOptions: ({
navigation
}) => (MY_HEADER_COMPONENT)},
....
})
Hopefully this answers your question

Cannot navigate to route from within navigation stack.

I have one file with my whole navigation stack. In my navigation header I have a menu and I want to open a Drawer. Now In this example I get the error: Cannot read property 'navigation' of undefined
My AppNavigation file:
import React from 'react';
import { Text } from 'react-native';
import { createStackNavigator, createDrawerNavigator } from 'react-navigation';
import Login from '../components/Login';
import Dashboard from '../components/Dashboard';
import NewNotification from '../components/NewNotification';
const GuestStack = createStackNavigator(
{
loginScreen: { screen: Login },
}, {
headerMode: 'float',
headerLayoutPreset: 'center',
navigationOptions: {
headerStyle: { backgroundColor: '#61b1cd' },
title: 'Welcome',
headerTintColor: 'black',
},
},
);
const LoggedinStack = createDrawerNavigator({
dashboard: { screen: Dashboard },
newNotifciation: { screen: NewNotification },
});
const LoggedinNavigation = createStackNavigator(
{
LoggedinStack: { screen: LoggedinStack },
}, {
headerMode: 'float',
navigationOptions: {
headerStyle: { backgroundColor: '#61b1cd' },
title: 'Welkom!',
headerTintColor: 'black',
headerLeft: <Text onPress = { () =>
this.props.navigation.openDrawer('dashboard')
// navigation.openDrawer('dashboard')
}>Menu</Text>,
},
},
);
const VveNavigator = createStackNavigator(
{
guestStack: {
screen: GuestStack,
},
loggedinStack: {
screen: LoggedinNavigation,
},
}, {
headerMode: 'none',
initialRouteName: 'guestStack',
},
);
export default AppNavigator;
The problem seems to be over here:
headerLeft: <Text onPress = { () =>
this.props.navigation.openDrawer('dashboard')
// navigation.openDrawer('dashboard')
}>Menu</Text>,
And then in my App.js I have
export default class App extends React.Component {
render() {
return (
<APPNavigator />
);
}
}
Version of react navigation is 2.18.1
Thanks
headerLeft doesn't receive navigation prop (check the source code). So if you'd like to use a navigation prop on press, you should consider to refactor your stack navigator config:
const LoggedinNavigation = createStackNavigator(
{
LoggedinStack: { screen: LoggedinStack },
}, {
headerMode: 'float',
navigationOptions: ({ navigation }) => ({ // here you get the navigation
headerStyle: { backgroundColor: '#61b1cd' },
title: 'Welkom!',
headerTintColor: 'black',
headerLeft: (
<Text
onPress={() => {
navigation.openDrawer()
}}
>
Menu
</Text>
),
}),
},
);
Check this issue for more options.

Couldn't get param in my tabs

I have Login and MAIN screen with 2 tabs...I'm passing user to MAIN screen with navigate('MAIN',{user: user} and I couldn't get that user in my MAIN with this.props.navigation.getParam('user'). My error is: undefined
When I debug with :
Reactotron.log(this.props); I'm getting undefined in my Main screen in constructor.
My code in App.js where is routes
const Routes = createStackNavigator(
{
Login: {
screen: Login,
navigationOptions: ({ navigation }) => ({
header: null,
}),
},
Main: {
screen: MainScreenRoutes,
navigationOptions: ({navigation}) => ({
header: null,
}),
},
},
{
initialRouteName: 'Login',
headerMode: 'screen',
navigationOptions: {
...HeaderStyles,
animationEnabled: true
}
}
);
export default Routes;
Code in MainRoutes:
let headerDefaultNavigationConfig = {
header: props => <CustomHeader {...props} />,
...HeaderStyles
};
const Tab1 = createStackNavigator(
{
Domov: {
screen: HomeScreen,
navigationOptions: {
},
},
},
{
navigationOptions: ({ navigation }) => ({
...headerDefaultNavigationConfig
}),
}
);
const Tab2 = createStackNavigator(
{
Dnevnik: {
screen: Diary,
navigationOptions: {
},
}
},
{
navigationOptions: ({ navigation }) => ({
...headerDefaultNavigationConfig
}),
}
);
const bottomTabs = createBottomTabNavigator(
{
Domov: Tab1,
Dnevnik: Tab2,
},
{
initialRouteName: "Domov",
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Domov') {
//iconName = `home${focused ? '' : '-outline'}`;
iconName='home';
} else if (routeName === 'Dnevnik') {
//iconName = `ios-calendar${focused ? '' : '-outline'}`;
iconName='ios-calendar';
}
// if focused return view with line
if(focused) {
return (
<View style={styles.item}>
<Icon name={iconName} style={{fontSize: 20, color: '#FFF'}} />
<View style={styles.line}></View>
</View>
);
} else {
return(
<Icon name={iconName} style={{fontSize: 20, color: '#FFF'}} />
)
}
},
}),
tabBarPosition: 'bottom',
tabBarOptions: {
activeTintColor: 'white',
showLabel: false,
inactiveTintColor: '#4C2601',
style: {
backgroundColor: '#033D51',
},
labelStyle: {
fontSize: 12,
lineHeight: 30,
},
},
swipeEnabled: true,
});
const All = createStackNavigator(
{
"Home":{
screen: bottomTabs,
navigationOptions: {
header: null,
},
},
"MyProfil":{
screen: MyProfil,
navigationOptions: ({ navigation }) => ({
...headerDefaultNavigationConfig,
headerTitle: 'Moj profil',
}),
},
"Help": {
screen: Help,
navigationOptions: ({ navigation }) => ({
...headerDefaultNavigationConfig,
headerTitle: 'Pomoč',
}),
}
},
{
initialRouteName: 'Home',
headerMode: 'screen',
navigationOptions: {
...HeaderStyles,
animationEnabled: true
}
}
);
export default All;
Code in HomeScreen: That alert gives me undefined
constructor(props) {
super(props);
let user = props.navigation.getParam('user');
alert(user);
}
Code in Login.js where I navigate to that screen with tabs;
var obj = {
id: json.user.id,
lastname: json.user.lastname,
name: json.user.name,
email: json.user.email,
user: json.user.user,
};
_storeData(obj);
setTimeout(() => {
navigate("Main",{user: JSON.stringify(obj)});
},1300);
This is good :
this.props.navigation.navigate("HomeScreen", { user :user });
try this :
let user = props.navigation.state.params.user ;
EDIT :
as the constructor is called only one time for each app start try this
import _ from "lodash";
...
constructor(props){ super(props) ; console.log("main constructor ") ; ... }
componentWillReceiveProps(nextProps) {
console.log(JSON.stringify(nextProps.navigation.state.params))
if (_.has(nextProps, "navigation.state.params.user")) {
console.log(nextProps.navigation.state.params.user );
this.setState({ user: nextProps.navigation.state.params.user })
}
}
EDIT 2
in my createStackNavigator in dont have
navigationOptions: { header: null},
just simple stack1: { screen: stack1 },
but in my stack screen component i have this
export default class stack1 extends React.PureComponent {
static navigationOptions = ({ navigation }) => ({ header: null });
constructor (props) {
super(props);
this.state = { };
}
componentDidMount() {
this.setState({ obsToEdit: this.props.navigation.state.params.obs, dataready: true });
}
}