5

I want to navigate from my reduc action file. 1st screen is login so after click on login button will call a redux action creator and reducer generate a new state. So, after the action i want to rediret to my dashboard.

I am using

react native + redux + react navigation

Login component file (LoginCmp.js):

import React, { Component } from 'react';
import {
  Text,
  View,
  ScrollView,
  KeyboardAvoidingView
} from 'react-native';
import { connect } from 'react-redux';
import { fieldChange, LoginAction } from '../../actions';
import { Button, Section, Input, Alert } from '../Helpers';

LoginAction(){
  const payload = {
    email: this.props.email,
    password: this.props.password
  };
  this.props.LoginAction(payload); // Action call
}


render() {
    return (
      <KeyboardAvoidingView
    style={styles.container}
    behavior="padding"
      >
      <View>
    <ScrollView contentContainerStyle={styles.contentContainer}>
      <Text style={styles.headerText}> Login </Text>
      {this.alertMessage()}
      <Section>
        <Input
          placeholder="[email protected]"
          onChangeText={this.onFieldChange.bind(this, { actionType: 'EMAIL_CHANGED' })}
          value={this.props.email}
        />
      </Section>
      <Section>
        <Input
          secureTextEntry
          placeholder="Password"
          onChangeText={this.onFieldChange.bind(this, { actionType: 'PASSWORD_CHANGED' })}
          value={this.props.password}
        />
      </Section>
      <Section>
        <Button
          onPress={this.LoginAction.bind(this)}
          style={styles.buttonLogin}
        >
          Submit
        </Button>
      </Section>
    </ScrollView>
      </View>
      </KeyboardAvoidingView>
    );
  }
}

const mapStateToProps = ({ auth }) => {
  console.log(auth);
  return auth;
};

export default connect(mapStateToProps, { fieldChange, LoginAction })(LoginCmp);

Router file (Router.js):

const RouterComponent = StackNavigator({
  login: { screen: LoginCmp },
  dashboard: { screen: DashboardCmp },
});

Action creator file (AuthActions.js):

import firebase from 'firebase';
import { NavigationActions } from 'react-navigation';


// Login actions
export const LoginAction = (payload) => {
  return (dispatch) => {
    firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
      .then(user => loginSuccess(dispatch, user))
      .catch((error) => {
    loginFail(dispatch, error);
    });
  };
};

// Login success function

logoutSuccess = (dispatch, user) => {
// dispatch an action
dispatch({
  type: 'LOGOUT_SUCCESS',
  payload: user
});  
### From here i want to navigate to dashboard.
};
1
  • You must subscribe redux state for login and change navigation when that state value is changed by redux action. It would be a right way. Commented Jan 7, 2022 at 17:53

7 Answers 7

9

EDIT: 9 Aug 2018

After the major rewrite of react-navigation, integrating with Redux is discouraged. There are, however, new tools to allow you to control navigation from anywhere. See, for example, how to create a NavigationService that provides this functionality

No Longer Valid - Don't do this

You haven't specified whether your navigation state is held in Redux, so if not, you should definitely integrate react-navigation and Redux.

The react-navigation documentation on how to do it is pretty clear.

After that, navigating becomes just another dispatch, only the actions come from react-navigation:

dispatch(NavigationActions.navigate({
  routeName: 'dashboard',
}));
Sign up to request clarification or add additional context in comments.

3 Comments

Take a look to the documentation, they really advise to not do this. Be careful.
@VincentDecaux At the time of writing this answer, Redux integration was part of the documentation. Since then, they have altered their approach, and it is now indeed inadvisable.
How can I pass an array of object from one to another screen while dispatch also how can I get that in the next screen Ex) dispatch(NavigationActions.navigate({ routeName: 'SettingsScreen', params: {id}}));
2
import firebase from 'firebase';
import { NavigationActions } from 'react-navigation';


// Login actions
export const LoginAction = (payload) => {
  return (dispatch) => {
    firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
      .then(user => loginSuccess(dispatch, user))
      .catch((error) => {
    loginFail(dispatch, error);
    });
  };
};

// Login success function

logoutSuccess = (dispatch, user) => {
  // dispatch an action
  dispatch({
    type: 'LOGOUT_SUCCESS',
    payload: user
  });  
  const navigateAction = NavigationActions.navigate({
      routeName: "dashboard",
      params: {},
      action: NavigationActions.navigate({ routeName: "dashboard" })
    });
  this.props.navigation.dispatch(navigateAction); // this is where you use navigation prop
};

// add this nav reducer to your root reducer

import Root from 'your navigation root path';

const navReducer = (state, action) => {
  const newState = Root.router.getStateForAction(action, state)
  return newState || state
}

export default navReducer;

Comments

2

Solution for v2 in 2018:

1) Define a NavigationService.js file

import { NavigationActions } from 'react-navigation';

let navigator;

 function setTopLevelNavigator(navigatorRef) {
  navigator = navigatorRef;
}

function navigate(routeName, params) {
  navigator.dispatch(
    NavigationActions.navigate({
       routeName,
       params,
     }),
  );
}


 export default {
  navigate,
  setTopLevelNavigator,
 };

2) Inside App.js you should have something like this: (redux provider, the store and the top level navigator set up before)

import AppNavigation from 'route-to-NavigationService';

<Provider store={store}>
    <TopLevelNavigator
      ref={(navigatorRef) => {
      NavigationService.setTopLevelNavigator(navigatorRef);
      }}
    />
</Provider>

3) Inside from your action: import NavigationService from 'route-to-NavigationService';

function logIn(){
     //async code
     ...
     dispatch(() => {
          NavigationService.navigate('RouteNameToNav'),
     });
}

Extra: If you want to reset your navigation stack (i.e Login should reset navigation stack), then inside your dispatch, your should do:

  dispatch(() => {
      StackActions.reset({
        index: 0,
        actions: [NavigationService.navigate('App')],
      });
    });

3 Comments

what is "TopLevelNavigator" where is it coming from in App.js? -1 for no guidence..
@TyForHelpDude As the name implies, it is the main navigator of your app. Usually is defined in your project set up.
Can you explain what is TopLevelNavigator ? I don't understand your solution
2

I have a quik and easy solution:

In the case where you have to navigate to specific screen, you can pass the navigation as a param to your redux action creator function

Example of lougout action:

Redux action:

export function handleLogout(navigation) {
    return (dispatch) => {
        dispatch(handleLoggingOut(true));
        setTimeout(() => {
            STORAGE.removeData('@FunnyLive:token').then(() => {
                dispatch(handleLoggingOut(false));
                navigation.navigate({routeName: 'Auth'});
            })
        }, 2000);
    }
}

mapDispatchToProps:

const mapDispatchToProps = (dispatch) => ({
  logout: (navigation) => dispatch(handleLogout(navigation))
})

Finally you have to call the action like this:

() => this.props.logout(this.props.navigation);

Comments

0

In navigation 5 and Redux

for examle I have component Login

const LoginScreen = (props) => {
        return (
                <View style={styles.continer}>
                    <Login navigation={props.navigation}/>
                </View>
        )
}

in component Login i have function login

import { connect} from 'react-redux';
import {userLogin} from './action/userAction';

const login =()=>{
    const {username,password, navigation } = props;
    userLogin(username,password, navigation )
}


const mapStateToProps = (state) => {
   return{
       username:state.auth.username,
       password:state.auth.password,
   }
  };



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

and in userAction file

export const userLogin = (username, password, navigation) => {
    return dispatch => {
        // .... any code
        loginSucess(dispatch, navigation)
    }
}

const loginSucess = (dispatch, navigation) => {
    dispatch({
        type: USER_LOGIN_SUCSESS,
    })
    navigation.replace("Home")
}

Comments

0

As described in react-navigation v6 docs. You can use the react-navigation functions from outside the react components.

// RootNavigation.js

import { createNavigationContainerRef } from '@react-navigation/native';

export const navigationRef = createNavigationContainerRef()

export function navigate(name, params) {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
}

// add other navigation functions that you need and export them

Navigate without the navigation props from docs for react-navigation v5

Comments

-1

one hacky way that worked for me is that you can send navigation prop to your action

<Button rounded block onPress={() => this.props.nav(this.props.navigation)}>
    <Text>
    nav
     </Text>
</Button>

then in your action file:

export function navAction(navigation) {
    return (dispatch) => {
        navigation.navigate('yourRoute')
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.