I'm using Xcode 10 & latest react-native version.
I created StackNavigator app with TabNavigator.
Code: navigation.js Class
import React from "react";
import { TabNavigator, StyleSheet, Text, View, Image} from "react-navigation";
import Dashboard from '.././Screen/Dashboard'
import Home from '.././Screen/Home'
import Events from '.././Screen/Events'
import Settings from '.././Screen/Settings'
export default Tab = TabNavigator({
Home: {
screen: Home,
},
Settings: {
screen: Settings,
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor }) => (
<Image source={require('.././assets/setting.png')}
style= {{width:15, height:15, tintColor:'black'}}>
</Image>
)
},
},
Events: {
screen: Events,
},
}, {
tabBarPosition: 'bottom',
swipeEnabled: true,
tabBarOptions: {
showIcon: true,
activeTintColor: '#f2f2f2',
activeBackgroundColor: "#2EC4B6",
inactiveTintColor: '#666',
labelStyle: {
fontSize: 16,
padding:4,
}
}
});
But i got error here,
[fatal][tid:com.facebook.react.ExceptionsManagerQueue] Unhandled JS Exception: Invariant Violation: Invariant Violation: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of TabBarIcon.
If i remove this line:
tabBarIcon: ({ tintColor }) => (
<Image source={require('.././assets/setting.jpeg')}
style= {{width:15, height:15, tintColor:'black'}}>
</Image>
)
then its working perfectly without icon.
i searched everything but don't find solution.
Please try this ( assuming u r creating a bottom navigator and you have latest react navigation )
import { createBottomTabNavigator } from 'react-navigation';
export default createBottomTabNavigator({
Home: {
screen: Home,
},
Settings: {
screen: Settings,
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor }) => (
<Image source={require('.././assets/setting.png')}
style= {{width:15, height:15, tintColor:'black'}}>
</Image>
)
},
},
Events: {
screen: Events,
},
}, {
tabBarPosition: 'bottom',
swipeEnabled: true,
tabBarOptions: {
showIcon: true,
activeTintColor: '#f2f2f2',
activeBackgroundColor: "#2EC4B6",
inactiveTintColor: '#666',
labelStyle: {
fontSize: 16,
padding:4,
}
}
});
Related
I am new to react native, I am trying to create a tab bar and also use createStackNavigator to allow me to link screens together. I have been able to get this to work with the following code.
const TabNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen
},
Events: {
screen: EventScreen
},
About: {
screen: AboutScreen
}
},
{ tabBarOptions: {
showIcon: true,
activeTintColor: '#D4AF37',
inactiveTintColor: 'gray',
style: {
backgroundColor: 'white',
},
labelStyle: {
fontSize: 20,
}
}
}
);
const MyStack = createStackNavigator({
Tabs: {
screen: TabNavigator
},
Home: {
screen: HomeScreen
},
Sermons: {
screen: SecondActivity
},
Map: {
screen: MapScreen
}
},
{
initialRouteName: 'Tabs',
}
);
export default createAppContainer(MyStack);
The only problem is that when I run my app each page says tabs in the header as shown below. Is there any way to fix this?
Try to set navigationOptions:
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation, screenProps }) => ({
title: `My home page`
})
}
Yes you can pass navigationOptions to your different stacks!
const ENTRYSTACK= createStackNavigator(
{
ENTRY: {
screen: ENTRYSCREEN,
navigationOptions: {
headerTitle: "Your Header Title",
headerTitleStyle:{
color: "white",
alignSelf: "center" // some styling if u want
},
headerStyle:{
backgroundColor: "#a51717"
}
}
}, some other screens/stacks ...
}
)
Current behaviour
After click login and logout couple of times and waiting on login page there is a memory leak error. This happens switching from createMaterialTopTabNavigator to a createSwitchNavigator page.
With this project the error can be reproduced.
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
in TabBar (at MaterialTopTabBar.tsx:92)
in TabBarTop (at createMaterialTopTabNavigator.tsx:84)
in Pager (at TabView.tsx:70)
in RCTView (at TabView.tsx:128)
in TabView (at createMaterialTopTabNavigator.tsx:136)
in MaterialTabView (at createTabNavigator.tsx:228)
in NavigationView (at createNavigator.js:80)
in Navigator (at SceneView.js:9)
Expected behaviour
Is expected no memory leaks after navigating between switchNavigator and materialTopTabNavigator pages.
Code sample
SignIn
import React from 'react';
import { Text, View, Button } from 'react-native';
// import { Container } from './styles';
export default function Dashboard({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center' }}>
<Text>SignIn</Text>
<Button title="Login" onPress={() => navigation.navigate('Dashboard')} />
</View>
);
}
Dashboard.js
import React from 'react';
import { Text, View, Button } from 'react-native';
// import { Container } from './styles';
export default function Dashboard({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center' }}>
<Text>SignIn</Text>
<Button
title="Logout"
onPress={() => navigation.navigate('SignIn')}
color="red"
/>
</View>
);
}
routes.js
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createMaterialTopTabNavigator } from 'react-navigation-tabs';
import SignIn from './pages/SignIn';
import Dashboard from './pages/Dashboard';
import Classroom from './pages/Classroom';
import Student from './pages/Student';
const styleTab = {
activeTintColor: 'blue',
labelStyle: {
fontSize: 20,
},
showIcon: false,
inactiveTintColor: '#DDD',
style: { elevation: 0 },
tabStyle: {
height: 80,
backgroundColor: '#fff',
},
scrollEnabled: true,
swipeEnabled: true,
upperCaseLabel: false,
};
const Routes = createAppContainer(
createSwitchNavigator(
{
SignIn,
App: createMaterialTopTabNavigator({
Dashboard: {
screen: Dashboard,
navigationOptions: {
tabBarVisible: true,
tabBarLabel: 'Dashboard',
tabBarOptions: styleTab,
},
},
Classroom: {
screen: Classroom,
navigationOptions: {
tabBarVisible: true,
tabBarLabel: 'Classroom',
tabBarOptions: styleTab,
},
},
Student: {
screen: Student,
navigationOptions: {
tabBarVisible: true,
tabBarLabel: 'Student',
tabBarOptions: styleTab,
},
},
}),
},
{
initialRouteName: 'SignIn',
},
),
);
export default Routes;
Screenshots (if applicable)
Login page after error
What have you tried
I have tried some solutions creating a NavigationService and with with navigation focus without success. I may be missing something, in this situations perhaps a simple thing.
Your Environment
Android 8.0
Ubuntu 18.04 LTS
react-navigation "^4.0.10",
react-navigation-tabs "^2.6.2"
node v10.15.3
yarn 1.21.1
Try adding "lazy" attribute to the Tab Navigator, this would defer the navigator from rendering the Screen until the users clicks on it. This would fix the memory leak error as well.
I have a problem with React Native Navigation Library, The problem is that I implemented logout in my application that forget the AsyncStorage presistent data, the problem starts when I log to another account without restarting the application, I find that the navigation drawer does not sense the change in AsyncStorage although I update the state depending on returned value from AsyncStorage as if it is cached, so I want a method to refresh the navigation draw or flush the navigation drawer cached view once I made a logout out and re-logged to another account to change the name and thumbnail content.
I tried to find any event listener or any callback where I can replace with my own logic but I didn't find anything closely related.
I also tried to replace AsyncStorage with axios call directly to fetch the user but nothing worked.
My Navigator Code:
import {createStackNavigator, createAppContainer, createDrawerNavigator} from 'react-navigation';
import {
Login,
Register,
ShowProperty,
AllProps,
Splash,
Search,
SearchResult,
EditProfile,
AddProperty,
Home,
HomeSearch,
Contact,
About,
} from "./pages";
import {NavDrawer} from "./components";
import {Dimensions} from 'react-native';
const StackNavigator = createStackNavigator(
{
Welcome: {
screen: Splash
},
Register: {
screen: Register
},
Login: {
screen: Login
},
ShowProps: {
screen: AllProps
},
ShowProp: {
screen: ShowProperty
},
Search: {
screen: Search
},
SearchResult: {
screen: SearchResult
},
EditProfile: {
screen: EditProfile
},
AddProperty: {
screen: AddProperty
},
Home: {
screen: Home,
},
HomeSearch: {
screen: HomeSearch,
},
About: {
screen: About,
},
Contact: {
screen: Contact,
},
},
{
initialRouteName: "Welcome",
headerMode: "none",
duration: 500,
lazy: true,
}
);
const DrawerNavigation = createDrawerNavigator({
Drawer: {
screen: NavDrawer,
},
Application: StackNavigator,
}, {
initialRouteName: "Application",
headerMode: "none",
duration: 500,
lazy: true,
contentComponent: NavDrawer,
drawerWidth: Dimensions.get('window').width,
drawerPosition: 'right',
});
export default createAppContainer(DrawerNavigation);
and this is my custom drawer code:
import React, {Component} from 'react';
import {ActivityIndicator, Image, ImageBackground, StyleSheet, View, TouchableOpacity} from 'react-native';
import Responsive from "./Responsive";
import AsyncStorage from '#react-native-community/async-storage';
import {FontText} from "./index";
import Icon from 'react-native-vector-icons/EvilIcons';
import axios from 'axios';
import {NavigationActions, StackActions} from "react-navigation";
class NavDrawer extends Component {
state = {
profile_picture: null,
name: null,
};
componentDidMount = async () => {
const user = await AsyncStorage.getItem('#UserData:user');
if(user !== null){
let {first_name, last_name, profile_picture} = JSON.parse(user).data;
console.log(first_name, last_name, profile_picture);
let stateObj = {
profile_picture: profile_picture ? profile_picture : null,
name: first_name && last_name ? first_name +" "+ last_name : null,
};
this.setState({
...stateObj
});
}
};
handleNavigation = (routeName) => (e) => {
this.props.navigation.closeDrawer();
this.props.navigation.navigate(routeName);
};
resetAndNavigate = (route) => {
let navigator = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
routeName: route,
}),
],
});
this.props.navigation.dispatch(navigator);
};
clearCredentials = async (e) => {
try{
await AsyncStorage.clear();
this.resetAndNavigate("Login");
}
catch (e) {
this.resetAndNavigate("Login");
}
};
render() {
return (
<ImageBackground source={require('../images/drawer-image.jpg')} style={style.backgroundStyle}>
<View style={style.infoWrapper}>
<Image source={this.state.profile_picture ?
{uri: this.state.profile_picture} :
require('../images/man.jpg')
} style={style.img}
/>
<FontText wFont={'bold'} style={style.nameStyle}>
{this.state.name ? this.state.name : "Loading.."}
</FontText>
</View>
<View style={style.navigators}>
<TouchableOpacity onPress={this.handleNavigation('Home')}>
<FontText style={style.nameStyle}>
Home
</FontText>
</TouchableOpacity>
<TouchableOpacity onPress={this.handleNavigation('About')}>
<FontText style={style.nameStyle}>
About us
</FontText>
</TouchableOpacity>
<TouchableOpacity onPress={this.handleNavigation('Contact')}>
<FontText style={style.nameStyle}>
Contact us
</FontText>
</TouchableOpacity>
<TouchableOpacity onPress={this.clearCredentials}>
<FontText style={style.nameStyle}>
Logout
</FontText>
</TouchableOpacity>
<TouchableOpacity style={style.dismiss} onPress={this.props.navigation.closeDrawer}>
<Icon name={"close"} color={"#fff"} size={35}/>
</TouchableOpacity>
</View>
</ImageBackground>
);
}
}
export default NavDrawer;
The expected is when I logged out and re-login with another account is to see the name and photo of current user in drawer.
The actual behavior is that navigation drawer caches the custom component for the drawer and when I log with another user I see the information of the previous user.
when I test App.js I have the following error that appears:
TypeError: Cannot read property 'createStackNavigator' of undefined
24 | borderBottomWidth:0,
25 | },
> 26 | headerTintColor: '#294c95',
| ^
27 | headerTitleStyle: {
28 | fontWeight: 'bold',
29 | color:'white',
the file that indicates, it is HomeNavigation.js. On the other hand the line that indicates is correct and in this file the code is correct
here is my test
import 'react-native';
import React from 'react';
import App from '../App';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
global.fetch = jest.fn(() => new Promise(resolve => resolve()));
jest.mock('react-native-gesture-handler', () => {});
jest.mock('react-navigation-stack', () => { BaseButton: {} });
//jest.mock('react-navigation', ()=>{}); //if I add or remove this line it doesn't change anything.
describe('App', ()=> {
it('renders correctly the App component', () => {
const tree = renderer.create(<App/>).toJSON();
expect(tree).toMatchSnapshot();
});
});
jest.mock('react-native-gesture-handler', () => {}) this line solves this problem: TypeError: Cannot read property 'State' of undefined
jest.mock('react-navigation-stack', () => { BaseButton: {} }); this line solves this problem: TypeError: Cannot read property 'BaseButton' of undefined
HomeNavigation.js
import React from "react";
import {createStackNavigator} from "react-navigation";
import {Screen1Screen} from "../Screen"; //whatever name
import {Icon} from "react-native-elements";
import {fromRight} from 'react-navigation-transitions';
import {CLR_MENU} from "../assets/styles/colors";
export const HomeNavigation = createStackNavigator({
Screen1: Screen1Screen // whatever name // this part is correct
},{
cardStyle: {
backgroundColor: 'black',
opacity: 1,
},
defaultNavigationOptions: (navigation) =>({
headerStyle: {
backgroundColor: [CLR_MENU],
borderBottomWidth:0,
},
headerTintColor: '#294c95', // the error point on this line
headerTitleStyle: {
fontWeight: 'bold',
color:'white',
},
headerRight:
<Icon
name = "menu"
size = {24}
color = "white"
onPress={_=>navigation.navigation.openDrawer()}
containerStyle={{marginRight:10}}
underlayColor={CLR_MENU}
/>,
}),
transitionConfig: () => fromRight(),
});
package.json
...
"jest": {
"preset": "react-native",
"setupFiles": [
"<rootDir>/src/setupJest.js"
],
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|react-navigation|react-navigation-redux-helpers|react-navigation-drawer)"
]
}
I think defaultNavigationOption is not a fat arrow function. From the docs of react-navigation:
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen
},
{
initialRouteName: 'Home',
/* The header config from HomeScreen is now here */
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
}
}
}
);
I wanted to know how I can add tab navigation and stack navigation with react navigation in react native.
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, Image, TouchableHighlight, ScrollView, Dimensions } from 'react-native';
import {StackNavigator,TabNavigator} from 'react-navigation';
import Scores from './src/scores.js';
import Profile from './src/profile.js';
import Favourite from './src/favourite.js'
const MyApp = TabNavigator({
Scores: {
screen: Scores,
},
Favs: {
screen:Favourite ,
},
Profile: {
screen:Profile,
},
}, {
tabBarPosition: 'bottom',
animationEnabled: false,
tabBarOptions: {
activeTintColor: '#F7C01C',
},
});
export default MyApp;
Here I have TabNavigation only working but I still need to add the stacknavigatio and maybe later I need to add Drawer Navigation.
You can nest Navigators. Just create a StackNavigator exactly as you created your TabNavigator and add it instead of a screen.
const MyFavs = StackNavigator({
FavouriteList: {
screen: FavouriteList,
},
ViewFavourite: {
screen: ViewFavourite,
},
}, {
initialRouteName: 'FavouriteList'
});
const MyApp = TabNavigator({
Scores: {
screen: Scores,
},
Favs: {
screen: MyFavs,
},
Profile: {
screen: Profile,
},
}, {
tabBarPosition: 'bottom',
animationEnabled: false,
tabBarOptions: {
activeTintColor: '#F7C01C',
},
});
export default MyApp;