2

I need help in understanding how can I redirect to a page after I get a response from web service using axios in react and redux using typescript. In my case, the page is directly redirected to a new page even before the response is generated. Below is the code snippet for the same.

## Component.jsx##

import * as React from 'react';
import { Constants } from '../../../constants';
import { withRouter } from 'react-router-dom';
import '../styles/LoginPage.css';
import { store } from '../../../store';
import addSessionID from './../actions/LoginAction';
const logo = require('../../../assets/images/logo.png');
const footer = require('../../../assets/images/veras-logo.png');

class Login extends React.Component<any, {}> {
  public refs: { username: HTMLInputElement,
                password: HTMLInputElement };
  constructor(props: any) {
    super(props);

    this.onSubmit = this.onSubmit.bind(this);
  }
  onSubmit(event: any): void {
    event.preventDefault();
    const headers: any = {
            'Authorization': 'Basic ' + window.btoa(this.refs.username.value + ':' + this.refs.password.value),
            'content-type': 'application/json'
          };
    const URL = 
    Constants.VERAS_API.SESSION.BASE_URL + 
    Constants.VERAS_API.SESSION.LOGIN + 
    Constants.VERAS_API.SESSION.APPLICATION_ID_STRING ;
    store.dispatch(addSessionID(URL, headers));
    // this.props.history.push('/Dashboard');
  }

  render() {
    const username = 'username';
    const password = 'password';
    return (
      <div className="full-container">
        <div className="login-container">
          <div className="login-body">
            <div className="login-header">
              <img src={logo} alt="" />
            </div>
            <h3>{Constants.LANGUAGES.EN_US.LOGIN.LABELS.LOGIN_FORM}</h3>
            <form
              name="form"
              method="post"
              className="login-form"
              onSubmit={this.onSubmit}
            >
              <div className="col-md-10">
                <ul>
                  <li>
                    <label>
                      {Constants.LANGUAGES.EN_US.LOGIN.LABELS.USERNAME_FIELD}
                    </label>
                    <input
                      type="text"
                      className="form-control"
                      name={username}
                      ref={username}
                      required={true}
                    />
                  </li>
                  <li>
                    <label>
                      {Constants.LANGUAGES.EN_US.LOGIN.LABELS.PASSWORD_FIELD}
                    </label>
                    <input
                      type="password"
                      className="form-control"
                      name={password}
                      ref={password}
                      required={true}
                    />
                  </li>
                </ul>

                <span className="forgotpass">
                  {Constants.LANGUAGES.EN_US.LOGIN.LABELS.FORGOT_PASSWORD_LINK}
                </span>
                <button className="login-btn" >
                  {Constants.LANGUAGES.EN_US.LOGIN.LABELS.LOGIN_BUTTON}
                </button>
              </div>
            </form>
            <span className="login-footer-logo">
              <img src={footer} alt="" />
            </span>
          </div>
        </div>
      </div>
    );
  }
}

export default withRouter(Login);

Action.tsx

import axios from 'axios';
import { Constants } from '../../../constants';

export default function addSessionID(apiUrl: string, headers: any): any {
  const URL =
    Constants.VERAS_API.SERVER.SCHEME +
    '//' +
    Constants.VERAS_API.SERVER.HOSTNAME +
    Constants.VERAS_API.SERVER.PORT;
  const finalURL = URL + apiUrl;
  console.log(URL);
  return function(dispatch: any) {
    axios
      .post(
        finalURL,
        {},
        {
          headers: headers
        }
      )
      .then(response => {
        if (response.data.sessionId) {
          // history.pushState('', '', '/Dashboard');
          dispatch({
            type: 'LOGIN_SUCCESSFUL',
            payload: response.data.sessionId
          });
        }
      })
      .catch(error => {
        dispatch({
            type: 'LOGIN_FAILED',
            payload: error
          });
      });
  };
}

Reducer.tsx

interface InitialState {
  session_id: string;
  login_status: boolean;
  error: string;
}

export const loginReducer = (
  state: InitialState = { session_id: '', login_status: false, error: '' },
  action: any
): any => {
  console.log('Reducer', action.payload);
  switch (action.type) {
    case 'LOGIN_SUCCESSFUL':
      state = { session_id: action.payload, login_status: true, error: ''};
      console.log(state);
      return state;
    case 'LOGIN_FAILED':
        state = {session_id: 'null', login_status: false, error: action.payload };
        console.log(state);
        return state;
    default:
      return state;
  }
};

store.tsx

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import combineReducers from './combinedReducer';

export const store = createStore(combineReducers, applyMiddleware(thunk));

combineReducer.tsx

import { combineReducers } from 'redux';
import { loginReducer } from './modules/user/reducers/LoginReducer';

export default combineReducers({
  loginReducer
});

App.tsx

import * as React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Login from './modules/user/components/Login';
import Dashboard from './modules/dashboard/components/Dashboard';
import './assets/css/App.css';

// const logo = require('./logo.svg');

class App extends React.Component<{}, {}> {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact={true} path="/" component={Login} />
          <Route exact={true} path="/Dashboard" component={Dashboard} />
        </Switch>
      </Router>
    );
  }
}

export default App;

index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import registerServiceWorker from './registerServiceWorker';
import './assets/css/index.css';
import { store } from './store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);
registerServiceWorker();

package.json

{
  "name": "veras-reach-typescript",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@types/react-router-dom": "^4.2.1",
    "axios": "^0.17.1",
    "react": "^16.1.1",
    "react-dom": "^16.1.1",
    "react-redux": "^5.0.6",
    "react-router-dom": "^4.2.2",
    "react-scripts-ts": "2.8.0",
    "redux": "^3.7.2",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.2.0"
  },
  "scripts": {
    "start": "react-scripts-ts start",
    "build": "react-scripts-ts build",
    "test": "react-scripts-ts test --env=jsdom",
    "eject": "react-scripts-ts eject"
  },
  "devDependencies": {
    "@types/jest": "^21.1.6",
    "@types/node": "^8.0.53",
    "@types/react": "^16.0.25",
    "@types/react-dom": "^16.0.3",
    "@types/react-router": "^4.0.17",
     "eslint": "^4.11.0"
  }
}

Can someone please help me with the redirection problem?

Advait
  • 74
  • 1
  • 3
  • 13
  • Check this answer https://stackoverflow.com/questions/44127739/programmatically-navigate-using-react-router/44128108#44128108 – Shubham Khatri Nov 22 '17 at 06:56

1 Answers1

2

You can detect changes in props and then can redirect to page in your component itself like

componentWillReceiveProps(newProps){
    if(newProps.login_status){ // Redirect if login status become true
       this.props.history.push('/Dashboard')
    }
}

Or you can check in render method like

render() {
    if (this.props.login_status) { // Redirect if login status true
         this.props.history.push('/Dashboard');
    }
    return <LoginComponent /> // Component name changed for understanding
}
Elumalai Kaliyaperumal
  • 1,498
  • 1
  • 12
  • 24
  • thank you, I have another doubt. The initial state that is set in my reducer has 'session_id' has ' ', when I click on login button it gives me the session_id that is stored in the redux i.e blank, because I didn't receive any response from the web service. Once again if I click on the button, It gives me the previous session_id and stores a new session_id from the web service. So how can I tackle this issue? – Advait Nov 22 '17 at 09:33
  • @Advait - Still you are getting previous session id instead of current session id? What you are getting from the store? Sorry If I am wrongly understood.. – Elumalai Kaliyaperumal Nov 22 '17 at 10:17
  • I am pasting my logs in the comments:-inside dispatch Login.tsx:38 ==== {session_id: "", login_status: false, error: ""} LoginReducer.tsx:11 Reducer bee03a9822824f8eb12a4773e287e4bb LoginReducer.tsx:15 {session_id: "bee03a9822824f8eb12a4773e287e4bb", login_status: true, error: ""} Login.tsx:38 ==== {session_id: "bee03a9822824f8eb12a4773e287e4bb", login_status: true, error: ""} LoginReducer.tsx:11 Reducer f0496644d3344d3fbfd8e73854de91bc LoginReducer.tsx:15 {session_id: "f0496644d3344d3fbfd8e73854de91bc", login_status: true, error: ""} – Advait Nov 22 '17 at 10:51
  • Also I am not able to use "dispatch(push('/Dashboard'))". instead of redirecting it gives me the logs for the dispatch – Advait Nov 22 '17 at 10:53
  • @Advait - Wrap initial state in your reducer like `return { ...state, session_id: action.payload, login_status: true, error: ''}` and try and `dispatch(push("/Dashboard"))` works only if you are using `react-router-redux`. So try alternate options as provided above. – Elumalai Kaliyaperumal Nov 22 '17 at 11:32
  • @Advait - I couldn't see `mapStateToProps` or `mapDispatchToProps` methods in your login component since you are using `redux`. Hope this will helps you! – Elumalai Kaliyaperumal Nov 22 '17 at 11:41
  • @Advait - As per your logs Yes `redux` store will have last inserted state initially then it will update the new state coming from reducer. So I recommend you to use `componentWillReceiveProps` method. – Elumalai Kaliyaperumal Nov 22 '17 at 11:59
  • thank you for all your suggestions componentWillReceiveProps(newProps){ if(newProps.login_status){ // Redirect if login status become true this.props.history.push('/Dashboard') } } worked and my problem is solved.Thank You – Advait Nov 28 '17 at 05:55
  • @Advait - If it really helped you please make answer as accepted. – Elumalai Kaliyaperumal Nov 28 '17 at 05:58