There is no route defined for key - react-native

I'm using react native, with redux and react navigation. I have everything setup, however, I'm getting a weird issue/error
In my reducer, I have the following
const initialNavState = {
index: 1,
routes: [
{ key: 'Login', routeName: 'Login' },
{ key: 'ResetPassword', routeName: 'ResetPassword' },
],
};
const initialAuthState = { isLoggedIn: false };
const AppReducer = combineReducers({
nav: (state = initialNavState, action) => {
switch(action.type) {
case 'Login':
return AppNavigator.router.getStateForAction(NavigationActions.back(), state);
case 'Logout':
return AppNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'Login' }), state);
case 'ResetPassword':
return AppNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'ResetPassword' }), state);
case 'Home':
return MainScreenNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'Home' }), state);
default:
return AppNavigator.router.getStateForAction(action, state);
}
}
});
export default AppReducer;
This works fine and I can navigate better my two views but when I add another route
{ key: 'Home', routeName: 'Home' },
I get the following error "There is no route defined for key must by one of login resetpassword.
Not sure what I'm doing wrong?
Updated my router
// Native tab navigation
export const TabsNavigation = TabNavigator({
Home: {
screen: Home,
navigationOptions: ({ navigation }) => ({
tabBarLabel: 'Home',
headerLeft : <DrawerIcon navigation={navigation} />,
tabBarIcon: ({ tintColor }) => <Icon name="home" size={28} color={tintColor} type={"font-awesome"} />
}),
},
Photos: {
screen: Photos,
navigationOptions: {
tabBarLabel: 'Photos',
tabBarIcon: ({ tintColor }) => <Icon name="camera" size={28} color={tintColor} type={"font-awesome"} />
},
},
SiteDiary: {
screen: SiteDiary,
navigationOptions: {
tabBarLabel: 'Site Diary',
tabBarIcon: ({ tintColor }) => <Icon name="cog" size={28} color={tintColor} type={"font-awesome"} />
},
},
});
export const AppNavigator = StackNavigator({
Login: {
screen: Login,
navigationOptions: {
title: "Login",
headerLeft: null
},
initialRouteName : 'Home'
},
ResetPassword: {
screen: ResetPassword,
navigationOptions: {
title: "Reset Password",
headerLeft: null
},
}
});
// Main navigation StackNavigator
export const MainScreenNavigator = StackNavigator({
Home: {
screen: TabsNavigation,
navigationOptions: {
title: "Home",
headerLeft: null,
}
}
});
Index.js (main)
// App state
const AppWithNavigationState = connect( state => ({ nav: state.nav})) (({ dispatch, nav }) => (
<AppNavigator navigation = { addNavigationHelpers ({ dispatch, state: nav })} />
));
class App extends React.Component {
store = createStore(AppReducer, undefined, autoRehydrate());
componentDidMount() {
persistStore(this.store, { storage: AsyncStorage });
}
render() {
return (
<Provider store={this.store}>
<AppWithNavigationState />
</Provider>
);
}
}
AppRegistry.registerComponent('App', () => App);
export default App;
I the core issue is with AppNavigator on my main file, I'm trying to have
AppNavigator -- this holds all the public login views
MainScreenNavigator -- This is the main app
and later add a darwer but right now would be nice to get just this working.
The issue is I'm not sure how you can jump between StackNavigator

Related

Backhandler quits app instead of going back to relative screen

Using nested stacks when I go back to my homescreen, my homescreen briefly shows, then the app quits. Instead of hardcoding the route to go back to, how can I go back to my homescreen without quitting the app?
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
onBackPress = () => {
const { dispatch } = this.props;
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "Home" })]
});
this.props.navigation.dispatch(resetAction);
};
App navigator:
const withHeader = (
screen: Function,
routeName: string,
Header
): StackNavigator =>
createStackNavigator(
{
[routeName]: {
screen,
navigationOptions: ({ routeName, props }) => ({
header: props => <Header {...props} />
})
}
},
{
initialRoute: "Home",
transparentCard: true,
cardStyle: {
backgroundColor: "transparent",
opacity: 1
},
transitionConfig: () => ({
containerStyle: {
backgroundColor: "transparent"
}
})
}
);
const routes = {
VideoEpisodes: {
screen: withHeader(VideoEpisodesScreen, "Video Episodes", DrawerHeader)
},
TestYourself: {
screen: withHeader(TestYourselfScreen, "Test Yourself", DrawerHeader)
},
MyResults: {
screen: withHeader(MyResultsScreen, "My Results", DrawerHeader)
},
BookmarkedVideos: {
screen: withHeader(
BookmarkedVideosScreen,
"Bookmarked Videos",
DrawerHeader
)
},
About: {
screen: withHeader(AboutScreen, "About", DrawerHeader)
}
};
const NestedDrawer = createDrawerNavigator(routes, config);
const MainStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
navigationOptions: ({ props }) => ({
header: props => <BasicHeader {...props} />
})
},
Drawer: {
screen: NestedDrawer,
navigationOptions: ({ props }) => ({
header: () => null
})
},
VideoPlayer: {
screen: VideoPlayerScreen,
navigationOptions: ({ props }) => ({
header: props => <BasicHeader {...props} />
})
}
},
{
initialRoute: "Home",
transparentCard: true,
cardStyle: {
backgroundColor: "transparent",
opacity: 1
},
transitionConfig: () => ({
containerStyle: {
backgroundColor: "transparent"
}
})
}
);
onBackPress = () => {
const { dispatch } = this.props;
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "Home" })]
});
this.props.navigation.dispatch(resetAction);
return true
};

Remove the navigation header from the react-native screen - stack navigation

I have a screen which has tab-bar navigation where each screen is of type stack navigation with a couple of screens defined in each. When I navigate from FamilyMembers to SingleContact screen I don't want to see the navigation bar with the back button on top. I want my view (the blue one) in single contact to start from the top. But it appears although I set the header to null! Please help.
//------------------- Single Contact Screen----------//
import { Text, AsyncStorage, Image, FlatList, Alert, ActivityIndicator, Platform, StyleSheet, View } from 'react-native';
import { Icon, Container, Spinner, Content, Left, Right, Header, ListItem } from 'native-base'
import profileService from '../services/Api/ProfileService';
import { SafeAreaView } from 'react-navigation';
HEADER_MAX_HEIGHT = 100
HEADER_MIN_HEIGHT = 60
PROFILE_IMAGE_MAX_HEIGHT = 80
PROFILE_IMAGE_MIN_HEIGHT = 40
export default class SingleContact extends Component {
constructor(props) {
super(props);
this.state = { userName: "", contacts: [], userID: "", cookie: null, memberShips: [] };
}
async componentDidMount() {
}
onDataLoaded(result, userName) {
}
render() {
return (
<SafeAreaView>
<View style={{ flex: 1 }}>
//--------------------App.js navigation setup --------------------------//
const FamilyMembersStack = createStackNavigator({
FamilyMembers: {
screen: FamilyMembers,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Family members",
}
}
},
SingleContact: {
screen: SingleContact,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Contact"
}
}
},
}
, {
mode: 'modal',
headerMode: 'none'
});
const HomeScreenStack = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
},
FamilyMembersStack: {
screen: FamilyMembersStack,
navigationOptions: ({ navigation }) => {
return {
header: null
}
}
},
AttendanceHistory: {
screen: AttendanceHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Attendance history"
}
}
},
OrderHistory: {
screen: OrderHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Order history"
}
}
}
});
HomeScreenStack.navigationOptions = {
tabBarLabel: 'My info',
tabBarIcon: ({ tintColor }) => (
<FaIcon name="user" size={20} color={tintColor} />
),
};
const ScheduleScreenStack = createStackNavigator({
Schedule: {
screen: ScheduleScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
}
});
ScheduleScreenStack.navigationOptions = {
tabBarLabel: 'Find a class',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-calendar" size={20} color={tintColor} />
),
};
const ShopScreenStack = createStackNavigator({
Shop: {
screen: ShopScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
}
});
ShopScreenStack.navigationOptions = {
tabBarLabel: 'Get a pass',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-basket" size={20} color={tintColor} />
),
};
const NotificationsScreenStack = createStackNavigator({
Notifications: {
screen: NotificationsScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
}
});
NotificationsScreenStack.navigationOptions = {
tabBarLabel: 'Notifications',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-alert" size={20} color={tintColor} />
),
};
const EventsStack = createStackNavigator({
Events: {
screen: Events,
navigationOptions: ({ navigation }) => {
return {
tabBarLabel: "Events",
tabBarIcon: ({ tintColor }) => (
<Icon name="md-calendar" size={20} />
),
headerLeft: (
<Icon name="md-menu" style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
size={30} />
)
}
}
}
});
EventsStack.navigationOptions = {
tabBarLabel: 'Events',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-calendar" size={20} color={tintColor} />
),
};
const DashboardTabNavigator = createBottomTabNavigator({
HomeScreenStack,
ScheduleScreenStack,
ShopScreenStack,
NotificationsScreenStack
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
header: null,
headerTitle: routeName,
}
},
tabBarOptions: {
activeTintColor: 'white',
inactiveTintColor: 'silver',
labelStyle: {
fontSize: 12,
},
style: {
backgroundColor: 'rgba(24,130,201,1);',
},
}
}, { initialRouteName: HomeScreenStack }
);
const DashboardStackNavigator = createStackNavigator({
DashboardTabNavigator: DashboardTabNavigator
});
const AppDrawerNavigator = createDrawerNavigator({
Dashboard: {
screen: DashboardStackNavigator
}
}, {
contentComponent: props => <DrawerContent {...props} />
});
const AppSwitchNavigator = createSwitchNavigator({
AuthLoading: AuthLoadingScreen,
Login: { screen: Login },
Dashboard: { screen: AppDrawerNavigator }
}, {
initialRouteName: 'AuthLoading',
}
);
const AppContainer = createAppContainer(AppSwitchNavigator);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
Did you already modify your FamilyMembersStack inside HomeScreenStack like this?
const HomeScreenStack = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
},
// modify this Stack
FamilyMembersStack:{
screen: FamilyMembersStack,
navigationOptions: ({ navigation }) => {
return {
header: null
}
}
}
AttendanceHistory: {
screen: AttendanceHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Attendance history"
}
}
},
OrderHistory: {
screen: OrderHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Order history"
}
}
}
});
Follow up answer, remove the following. so that the header will render on the designated screen:
export default class SingleContact extends Component {
static navigationOptions = {
header: null, // remove this
}
constructor(props) {
super(props);
this.state = { userName: "", contacts: [], userID: "", cookie: null, memberShips: [] };
}
async componentDidMount() {
}
onDataLoaded(result, userName) {
}
render() {
//------------------------------//
const FamilyMembersStack = createStackNavigator({
FamilyMembers: {
screen: FamilyMembers,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Family members",
header:null
}
}
},
SingleContact: {
screen: SingleContact,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Contact",
header:null // and remove this
}
}
},
});

Functions are not valid as a React child (React-Native)

I can not wrap my head around and understand why am I given this warning, I am using two kinds of navigators ( tab navigator and stack navigator ), in App.js and I cannot seem to get them working correctly
App.js
export const Tabs = TabNavigator({
'FormScreen': {
screen: FormScreen,
navigationOptions: {
tabBarLabel: 'Contact Us',
tabBarIcon: ({ tintColor }) => <Icon name="ios-contact" type="entypo" size={28} color={tintColor} />
}
},
'ListScreen': {
screen: ListScreen,
navigationOptions: {
tabBarLabel: 'Contact List',
tabBarIcon: ({ tintColor }) => <Icon name="list" type="entypo" size={28} color={tintColor} />
}
}
});
export const NavigationScreen = () => {
return StackNavigator(
{
Tabs: {
screen: Tabs,
navigationOptions: {
gesturesEnabled: false
}
}
},
{
headerMode: "none",
mode: "modal"
}
);
};
export default class App extends React.Component {
render() {
return (
<NavigationScreen/>);
}
}

Force scrollview to re-render when closing a react-navigation modal?

I'm opening a modal, nested in a react-navigation TabNavigator.
This modal is used to add, say a teammate, to a Realm database.
When the new teammate is saved, I close the modal and "navigate" back to a ScrollView displaying all the teammates, retrieved from my Realm database.
My problem is that this ScrollView doesn't re-render when closing the modal.
I am not using Redux or any other state manager.
This is the code executed when saving a user:
onButtonPress() {
var teammate = new TeammateModel(this.firstname, this.lastname);
if (this.firstname && this.lastname) {
TeammateService.save(teammate);
this.props.navigation.goBack(null);
}
}
And this is the code of the for the component rendering the ScrollView:
export default class Team extends Component {
componentWillMount() {
teammates = TeammateService.findAll();
}
render() {
return (
<ScrollView>
<List>{teammates.map((teammate) => (
<ListItem
key={teammate.id}
title={`${teammate.firstname} ${teammate.lastname}`}
/>
))}
</List>
</ScrollView>
);
}
}
As requested here's also my routes.js where the navigation happens:
export const TeamStack = StackNavigator({
Team: {
screen: Team,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Team',
headerRight: <Button title="Add" onPress={() => navigation.navigate('EditTeammate')} />
}),
},
})
export const EditTeammateStack = StackNavigator({
EditTeammate: {
screen: EditTeammate,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Teammate',
headerLeft: <Button title="Cancel" onPress={() => navigation.goBack(null)} />
}),
}
})
export const NoteStack = StackNavigator({
EditNote: {
screen: EditNote,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Edit note'
})
}
})
export const Tabs = TabNavigator({
EditNote: {
screen: NoteStack,
navigationOptions: ({ navigation }) => ({
header: { visible: true },
headerTitle: 'Edit note',
tabBarLabel: 'Notes',
tabBarIcon: ({ tintColor }) => <Icon name="list" size={20} color={tintColor} />
}),
},
Team: {
screen: TeamStack,
navigationOptions: ({ navigation }) => ({
header: { visible: true },
headerTitle: 'Team',
tabBarLabel: 'Team',
tabBarIcon: ({ tintColor }) => <Icon name="users" size={20} color={tintColor} />
}),
}
}, {
initialRouteName: 'Team',
});
export const Root = StackNavigator({
Tabs: {
screen: Tabs,
},
EditTeammate: {
screen: EditTeammateStack,
},
}, {
mode: 'modal',
headerMode: 'none'
});
export default Root;
I'm sure I'm doing one (or more) thing(s) wrong. But what? :)

Cannot read property 'navigation' of undefined

I'm trying to navigate with NavigationActions, but for some reason it won't navigate.
I'm trying to move from LoginScreen to HomeScreen.
loginscreen:
constructor(props){
super(props)
this.state = {
email: '',
password: '',
status: '',
}
this.handlePress = this.handlePress.bind(this)
}
handlePress(){
firebaseRef.auth().signInWithEmailAndPassword(this.state.email, this.state.password).then(function(firebaseUser){
//Success, move to homepage.
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Home'})
]
})
this.props.navigation.dispatch(resetAction) <-- SAYS NAVIGATION IS UNDEFINED
}).catch(function(error){
//Failed to log in, print error.
console.log(error)
});
}
this is where I call handlePress:
<TouchableOpacity style={styles.logBtn} onPress={()=>this.handlePress()}>
<Text style={styles.logTxt}>
Login
</Text>
</TouchableOpacity>
This is 'navigation'(in render method, loginscreen):
const { navigation } = this.props.navigation;
this is app.js where I set the navigation:
import React from 'react';
import { AppRegistry } from 'react-native';
import { StackNavigator, TabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import LoginScreen from './app/screens/LoginScreen';
import RegisterScreen from './app/screens/RegisterScreen';
import HomeScreen from './app/screens/HomeScreen';
import FriendsScreen from './app/screens/FriendsScreen';
const Stylelist = StackNavigator({
Login:{
screen: LoginScreen,
navigationOptions: ({navigation}) =>({
header: null,
}),
},
Register:{
screen: RegisterScreen,
navigationOptions: ({navigation}) =>({
header: null,
}),
},
Home:{
screen: TabNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
title: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
)
}),
},
Friends: {
screen: FriendsScreen,
navigationOptions: ({ navigation }) => ({
title: 'Friends',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-people' : 'ios-people-outline'}
size={26}
style={{ color: tintColor }}
/>
)
}),
},
}),
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerStyle: {backgroundColor: "#553A91"},
headerTitleStyle: {color: "#FFFFFF"},
}),
}
});
export default Stylelist;
I tried to log the error from the 'catch' and I get this error:
Cannot read property 'navigation' of undefined
How can I fix it?
It should be
const { navigate} = this.props.navigation;
or
const { navigation } = this.props;
Actually, what you get in props is navigation object, which has navigate method in it.And what you were doing was
const { navigation } = this.props.navigation;
This gets evaluates to
this.props.navigation.navigation
It says look for navigation property inside navigation object, which actually is not present, hence giving undefined. I hope this clears your doubt.
I had this problem too.
Of course I had used setTimeout. There may be someone who has this problem, so it's a good reminder.
only use let that = this;
componentDidMount() {
let that = this ;
setTimeout(function () {
let toHome = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({routeName: 'MainScreen'})]
});
that.props.navigation.dispatch(toHome);
},3000);
}
Make sure your function is bind with this.
onPress={()=>this.handlePress()}
instead
onPress={()=>this.handlePress.bind(this)}