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); });
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With