Can we redirect to in reduxSaga
Asked Answered
H

2

8

I've a login page with HOC I pass component which must render be after successful login.

Here, if I check for isLoggedIn and redirect in render of sigin-in for then I get error

err: Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops

saga.js

           try{//call api
                //put login success
              <Redirect to="/app"/>        
            }

index.js

          const AuthProfile=requireAuth(App);

           In reactdom
             <Route render={(props)=><AuthProfile  {...props}/>} path="/app"/>  


          import React, { PropTypes } from 'react';  
          import { connect } from 'react-redux';  
          import { push } from 'react-router-redux';
          import { bindActionCreators } from 'redux';

          export default function (ComposedComponent) {  
            class Authenticate extends React.Component {


              componentDidMount() {
                console.log("12ra")
                this._checkAndRedirect();
              }

              componentDidUpdate() {
                this._checkAndRedirect();
              }

              _checkAndRedirect() {
                const { isLoggedIn, redirect } = this.props;

                if (!isLoggedIn) {
                  redirect();
                }
              }

              render() {
                console.log("28ra")
                return (
                  <div>
                    { this.props.isLoggedIn ? <ComposedComponent {...this.props} /> : null }
                  </div>
                );
              }
            }

            const mapStateToProps = (state) => {
              return {
                isLoggedIn:state.signInReducer.isLoggedIn
              };
            };

            const mapDispatchToProps = dispatch => bindActionCreators({
              redirect: () => push('/')
            }, dispatch)

            //Authenticate.propTypes = propTypes

            return connect(
              mapStateToProps, 
              mapDispatchToProps
            )(Authenticate);
          }       

Is HOC component correct or I'm missing on something?

Is it good practise to redirect in saga?

Can anyone please lemme know how do I get to app component after success i'm stuck there please help thanks

UPDATE

saga.js

       yield put({type:LOGIN_SUCCESS,payload:data})
        yield put(push('/app'))

index.js

Ex for Page1,Page2 I need

        <AuthRoute
      exact
      path="/"
      component={Page1}
      redirectTo="/login"
      authenticated={this.props.isLoggegIn}
    />

     <AuthRoute
      exact
      path="/"
      component={Page2}
      redirectTo="/login"
      authenticated={this.props.isLoggegIn}
    />
Heist answered 17/5, 2019 at 10:5 Comment(0)
G
8

Following is the way where you can navigate from saga:

saga.js

import { push } from 'react-router-redux';
...
// after API call & validate user
yield put(push('/app'));

index.js

 <Route strict exact path='/app' component={App}>
 <AuthRoute
          exact
          path="/"
          component={Yourcomponent}
          redirectTo="/login"
          authenticated={hasAccessToken()}
        />
Gaultiero answered 17/5, 2019 at 10:9 Comment(9)
for route its HOC, if loggedin then show component else login screen. will that work I want authentication for component must not be accessed without loginHeist
Updated my answer, if you required authentication (here I have considered token based authentication) you can used AuthRouteGaultiero
please check the updated code in saga.js is that the way we write . the other thing is i dont have access token authroute is build in library ?I'm confused {Yourcomponent} can be "app" or app must have different route?Heist
Yes you have written right code, it can be a seperate action and calling that action would be fine. It is okay if you don't have access token you can remove that part or can add yours mechanism to validate user is logged in or not and check that instead of hasAccessToken()Gaultiero
Please check I've updated the code the saga as well the indexHeist
I dont think redirect in props required anymoreGaultiero
can you please update your code. AuthRoute is requireAuth right?Heist
What I need to update?? AuthRoute is type of Route from react-router-auth package it is not a function/method it is type of route which will help you to automatically rediret to login if the user is invalidate/session expires/ anything else happensGaultiero
FYI- react-router-redux has been deprecated. They suggest using connected-react-router. Code is the same as above. npmjs.com/package/connected-react-router. github.com/reactjs/react-router-reduxFencible
M
8

I am going to tell you the best and the simplest way from which you can redirect in any part of the application(i.e. inside redux and outside as well).

Step: 1 Create history.js file.

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

Step : 2 Import it inside App.js file (or, where you have made routers of your application).

import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import history from './history';

const App = () => {
    return (<Router history={history}>
        <div className='App'>
            <Switch>
                <Route exact path={ROUTES.NOTIFICATIONS} component={Notification} />
                <Route exacr path={ROUTES.USER_PROFILE} component={UserProfile} />
                <Route exact path={ROUTES.SIGN_IN} component={SignInPage} />
                <Route exact path={ROUTES.SIGN_UP} component={SignUpPage} />
                <Route path='*' component={SignInPage} />
            </Switch>
        </div>
    </Router>
    );
};

export default App;

Step: 3 Inside Saga file just import the history.

import { push } from 'react-router-redux';
import { Auth } from "../service/api/Auth";
import history from '../containers/App/history';
import * as ACTION from '../constants/ActionType';
import { put, takeLatest, call } from "redux-saga/effects";
import { userLoginSuccess, userLoginFailed } from "../actions/auth";

export function* userLogin(loginData) {

  const payLoad = loginData.payload;
  try {
    const loginUserData = yield call(Auth.userLoginApiCall, payLoad);
    yield put(userLoginSuccess(TOKEN));
    history.push('/posts'); //  Redirect to Post Page
  } catch (err) {
    yield put(push(userLoginFailed()))
  }
}

export default function* userLoginRequest() {

  yield takeLatest(ACTION.USER_LOGIN_REQUEST, userLogin);
}
Matte answered 14/4, 2020 at 14:25 Comment(1)
Interesting, I used to wait for the result of the saga using useEffect inside of the component, which was quite tedious.Distich

© 2022 - 2024 — McMap. All rights reserved.