Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect from axios interceptor with react Router V4?

I want to make a redirection in axios interceptors when receiving a 403 error. But how can I access the history outside React components ?

In Navigating Programatically in React-Router v4, it's in the context of a React Component, but here i'm trying in axios context

axios.interceptors.response.use(function (response) {     // Do something with response data     return response;   }, function (error) {     // Do something with response error     if(error.response.status === 403) { console.log("Redirection needed !"); }      // Trow errr again (may be need for some other catch)     return Promise.reject(error); }); 
like image 718
hilderic sb Avatar asked Apr 04 '17 14:04

hilderic sb


Video Answer


1 Answers

I solved that by accessing my Redux Store from outside the Component tree and sending it my same action from the logout button, since my interceptors are created in a separated file and loaded before any Component is loaded.

So, basically, I did the following:

At index.js file:

//....lots of imports ommited for brevity import { createStore, applyMiddleware } from 'redux'; import reduxThunk from 'redux-thunk'; import reducers from './reducers'; import { UNAUTH_USER } from './actions/types'; //this is just a constants file for action types.  const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore); const store = createStoreWithMiddleware(reducers);  //Here is the guy where I set up the interceptors! NetworkService.setupInterceptors(store);  //lots of code ommited again... //Please pay attention to the "RequireAuth" below, we'll talk about it later  ReactDOM.render(   <Provider store={store}>       <BrowserRouter>           <div>               <Header />               <main className="plan-container">                   <Switch>                       <Route exact path="/" component={Landing} />                       <Route exact path="/login" component={Login} />                       <Route exact path="/signup" component={Signup} />                       <Route exact path="/calendar" component={RequireAuth(Calendar)} />                       <Route exact path="/profile" component={RequireAuth(Profile)} />                   </Switch>               </main>           </div>       </BrowserRouter>   </Provider>   , document.querySelector('.main-container')); 

And at the network-service.js file:

import axios        from 'axios'; import { UNAUTH_USER } from '../actions/types';  export default {   setupInterceptors: (store) => {      // Add a response interceptor     axios.interceptors.response.use(function (response) {         return response;     }, function (error) {         //catches if the session ended!         if ( error.response.data.token.KEY == 'ERR_EXPIRED_TOKEN') {             console.log("EXPIRED TOKEN!");             localStorage.clear();             store.dispatch({ type: UNAUTH_USER });         }         return Promise.reject(error);     });    } }; 

Last, but not least, I have a HOC (Higher Order Component) that I wrap my protected components where I do the actual redirect when the session is out. That way, when I trigger the action type UNAUTH_USER, it sets my isLogged property at my session reducer to false and therefore this component gets notified and does the redirect for me, at any time.

The file for require-auth.js component:

import React, { Component } from 'react'; import { connect } from 'react-redux';  export default function(ComposedComponent) {      class RequireAuth extends Component {          componentWillMount() {             if(!this.props.session.isLogged) {                 this.props.history.push('/login');             }         };          componentWillUpdate(nextProps) {             if(!nextProps.session.isLogged) {                 this.props.history.push('/login');             }         };          render() {             return <ComposedComponent {...this.props} />         }     }      function mapStateToProps(state) {         return { session: state.session };     }      return connect(mapStateToProps)(RequireAuth); } 

Hope that helps!

like image 177
DccBr Avatar answered Sep 20 '22 14:09

DccBr