Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot read property undefined of undefined #1919

Closed
ODelibalta opened this issue Jun 18, 2017 · 11 comments
Closed

Cannot read property undefined of undefined #1919

ODelibalta opened this issue Jun 18, 2017 · 11 comments
Labels

Comments

@ODelibalta
Copy link

Current Behavior

I am very new to react and pretty much all this stack. What I am trying to accomplish is to implement a tab navigator inside a stack navigator. I've done this without redux using this library but I can not do it when I move my stack navigator to redux. I've even tried a different navigation library and I keep ending up with that error in the title which is driving me crazy because it does not tell much (or I just do not get it).

I've used the exact redux example available in the examples repo. everything works until I change my home screen (the one after login) to a tab navigator I've created.

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addNavigationHelpers, StackNavigator, TabNavigator } from 'react-navigation';

import LoginScreen from '../screens/auth/LoginScreen';
import HomeScreen from '../screens/HomeScreen'; 
import HomeRoutes from '../routes/HomeRoutes';
 
export const AppNavigator = StackNavigator({
  Login: { screen: LoginScreen },
  Home: { screen: HomeScreen }, 
});

const AppWithNavigationState = ({ dispatch, nav }) => (
  <AppNavigator navigation={addNavigationHelpers({ dispatch, state: nav })} />
);

AppWithNavigationState.propTypes = {
  dispatch: PropTypes.func.isRequired,
  nav: PropTypes.object.isRequired,
};

const mapStateToProps = state => ({
  nav: state.nav,
});

export default connect(mapStateToProps)(AppWithNavigationState);

My HomeRoutes.js file

import React from 'react';
import { TabNavigator } from 'react-navigation';  

import JustTextScreen from '../screens/JustTextScreen';  
   

const HomeRoutes = TabNavigator( 
  { 
    Schedule: {
      screen: JustTextScreen,
      path: '' 
    }
  }  
);

export default HomeRoutes;

Just text screen file

import React, { Component } from 'react'; 
import { Text } from 'native-base';
 
class JustTextScreen extends Component { 
  render() {
    return ( 
      <Text>just the text screen</Text>
    );
  }  
}   
export default JustTextScreen; 

Expected Behavior

Your Environment

"dependencies": {
    "axios": "^0.16.2",
    "expo": "17.0.0",
    "native-base": "^2.1.5",
    "react": "16.0.0-alpha.6",
    "react-native": "https://github.com/expo/react-native/archive/sdk-17.0.0.tar.gz",
    "react-native-easy-grid": "^0.1.13", 
    "react-native-vector-icons": "^4.2.0",
    "react-navigation": "^1.0.0-beta.11",
    "react-redux": "^5.0.5",
    "redux": "^3.7.0",
    "redux-persist": "^4.8.0",
    "redux-thunk": "^2.2.0"

I've literally spent about 7 hours on my saturday to figure this out. Please please help. I have no idea what I am doing wrong or if this is a bug (I bet that it is me though) and I can use some light into this depressed dark state that is my soul.

@richmonkeys
Copy link

I don't understand how is HomeRoutes relevant from your code above. You import it but you never use it.
Please give us your HomeScreen code as well.

In the meantime, do have a look at my reply here. I believe you are facing something similar to this.
#1111 (comment)

@Velissel
Copy link

I am having the same issue

@nicemanis
Copy link

nicemanis commented Jun 28, 2017

I also have the same issue.
The error occurs when I call Navigator.router.getStateForAction with both action and state passed. If pass only action, it works as expected (Check react navigation docs).

EDIT:
Checked the StackRouter and TabRouter source code - I have a TabRouter nested under a StackRouter and it seems that StackRouter passes childRoute instead of the state to the TabRouter (see line 150 of the StackRouter definition).
What am I doing wrong?

@crazyyuan
Copy link

I also have the same issue.
When I inside a normal screen into StackNavigator in front of TabNavigator screen(the first),it works,why?

@boliveira
Copy link

Hi,

I am having the same issue and I believe the problem is in the way we initialize the navigation state in redux.

The docs say to do something like this to set the initial navigation state:

const initialState = AppNavigator.router.getStateForAction(AppNavigator.router.getActionForPathAndParams('Main'));

If AppNavigator is a StackNavigator and "Main" route is a DrawerNavigator (or TabNavigator), it will crash, because the StackRouter associated with the StackNavigator doesn't initialize the child router when it receives an action of navigate and its inner state isn't initialized.

So I ended up doing something like this:

import { NavigationActions } from "react-navigation";
import AppNavigator from "../AppNavigator";

//Force a Init of the main router
let initialNavState = AppNavigator.router.getStateForAction(
  NavigationActions.init()
);

const firstAction = AppNavigator.router.getActionForPathAndParams("Main");

//Then calculate the state with a navigate action to the first route, sending the previous initialized state as argument
initialNavState = AppNavigator.router.getStateForAction(
  firstAction,
  initialNavState
);

With this approach, it worked correctly.
I don't know if the StackRouter needs to change or the approach to setup redux integration needs to change...

@almirfilho
Copy link

@boliveira thanks a LOT for that.

However, I've noticed that you just need to do:

let initialNavState = AppNavigator.router.getStateForAction(
  NavigationActions.init()
);

No need for that:

const firstAction = AppNavigator.router.getActionForPathAndParams("Main");

//Then calculate the state with a navigate action to the first route, sending the previous initialized state as argument
initialNavState = AppNavigator.router.getStateForAction(
  firstAction,
  initialNavState
);

At least in my case =^)

@boliveira
Copy link

@almirfilho, I thought that so but there a was a particular case in my app that wasn't working with just the Init. I had to explicitly call getStateForAction for the first screen in the app to make it work.
I am not sure why though, because the state generated after the call with Init is pretty ok to me...
Anyway I am pretty sure there is a bug in the way StackRouter initializes its state, so while there isn't an official fix, I will use this workaround.

So I advise you to do the same to avoid problems in the future.

@boliveira
Copy link

boliveira commented Jul 13, 2017

@almirfilho , you were right, if I only do the init thing, it works as well. The problem I was having was not related to navigation. And this approach has a distinct advantage because if you do only the init, and have StackNavigators inside one of the routes of the DrawerNavigator, these routes would NOT be duplicated or triplicated like they were if you initialized the state using the recommended approach in the docs... There is really some kind of bug in the way the StackNavigator inside a DrawerNavigator is handled right now.

EDIT: Corrected "these routes would be duplicated" to "these routes would NOT be duplicated"

@juan-quiver
Copy link

@almirfilho it probably works with just the NavigationActions.init() in our case because we're already specifying initialRouteName: 'Tabs' on the navigator config?

@vonovak
Copy link
Member

vonovak commented Nov 3, 2017

Closing since the question seems to be answered. 👍

@yqz0203
Copy link

yqz0203 commented Jan 16, 2018

@boliveira I tried using NavigationActions.init(), but it seemed render two screen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests