-1

I am new to Redux and I don't understand what is wrong with the following set up. I got error: TypeError: TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')

For actions, I have a function for login:

export const loginWithEmail = ({email, password}) => async (dispatch) => {
    dispatch({type: "LOADING"})
    try {
        let user = await auth.signInWithEmailAndPassword(email, password);
        dispatch({type: "LOGIN_SUCCESS", payload: user})
    } catch (error) {
        dispatch({type: "LOGIN_FAILURE"})
    }
}

Login component:

class Login extends Component {
  componentWillReceiveProps(nextProps) {
    if(!_.isEmpty(nextProps.user)) {
      this.props.navigation.navigate('Home');
    }
  }

  login() {
    const {email, password} = this.props;
    this.props.loginWithEmail({email, password});
  }

  render() {
    return (
      ...
    )
  }
}

const mapStateToProps = state => {
  return {
    email: state.auth.email,
    password: state.auth.password,
    error: state.auth.error,
    user: state.auth.user
  }
}

export default connect(mapStateToProps, {loginWithEmail})(Login);

In my App.js

const AuthStack = createStackNavigator({
  Login: { screen: Login }
});

const MainStack = createStackNavigator(
  {
    Home: { screen: 'Home' },
    Auth: AuthStack
  },
  {
    initialRouteName: 'Home'
  }
);

const AppContainer = createAppContainer(MainStack);

export default class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
    return (
      <Provider store={store}>
        <AppContainer/>
      </Provider>
    );
  }
}

I did also try to use the Login component in another component like this:

const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
...
    <Provider store={store}>
        <Login navigation={this.props.navigation}/>
    </Provider>

My react-navigation version is 3.2.1

Update: tried following the solution from React Native: TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate') but no success

JAM
  • 565
  • 2
  • 9
  • 22
  • Possible duplicate of [React Native: TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')](https://stackoverflow.com/questions/47478570/react-native-typeerror-undefined-is-not-an-object-evaluating-this-props-navi) – Kai Mar 08 '19 at 23:25
  • If you remove `` and your redux is not working, then you might have some other redux issue. – Sean Wang Mar 08 '19 at 23:29
  • @Kai solution from the link did not work :( – JAM Mar 08 '19 at 23:37
  • It has nothing to do with redux. – 10101010 Mar 09 '19 at 05:10

1 Answers1

0

It's because of the other file where you are using Login screen component directly.

<Provider store={store}>
    <Login/>
</Provider>

This will not if you are expecting this.props.navigation to have a value. The solution here would be to remove this other use of Provider.

The following that you have already is enough to connect to Redux.

<Provider store={store}>
    <AppContainer/>
</Provider>
Sean Wang
  • 697
  • 5
  • 14
  • Not sure if I follow, what if I need to use the Login component in another file? Should I entirely rely on App.js? – JAM Mar 08 '19 at 23:29
  • So from what I can tell, you have the `Login` component setup as a "screen". So the only place `Login` should be used is within the react-navigation router stack. If you want `Login` to be a reusable component then you should not be using it within react-navigation stack. Instead you would have something like a `LoginScreen` component which uses the `Login` component. I can clarify and expand more if needed. – Sean Wang Mar 08 '19 at 23:32
  • @JacobMarsellos also notice how in the examples https://redux.js.org/basics/store they only create the store once in index.js. You should only be creating the store once at the top level. So you only need to create it once in your App.js. The Provider allows all the other components to be able to connect to the store via the connect function. – Sean Wang Mar 08 '19 at 23:36
  • The reason I have another component calling Login as a child component is because I also have a sign up component. And this parent component contains both login and signup. According to what you said above, should I have this parent component as a Screen? In this case, I can't really just remove this use of Provider – JAM Mar 08 '19 at 23:43
  • If your component is within a screen that is connected to redux then you can just pass down the items you need into your component. – Sean Wang Mar 09 '19 at 15:25
  • So if you have your top most level component connect to the redux store, then every component will be able to access redux. without using provider all over the place. – Sean Wang Mar 09 '19 at 15:27
  • Does this make sense? since `` is wrapped by the provider, every single component within will be able to use the redux connect function. – Sean Wang Mar 09 '19 at 15:32
  • A working example might help you https://alligator.io/react/react-native-redux/ Notice they only wrap provider once, but every single component can use the redux connect function. So you don't need to wrap every single component in Provider. – Sean Wang Mar 09 '19 at 15:35
  • Thank you, was away for a day and your comments made sense, I got it working – JAM Mar 10 '19 at 17:14