Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Access History Object Outside of a React Component

First of all, I am pretty familiar with the withRouter HoC, however, in this case, it doesn't help because I do not want to access the history object in a component.

I am trying to achieve a mechanism that will redirect the user to the login page if I receive back a 401 from a API endpoint. For making http requests I am using axios. I have around 60 endpoints that I need to cover, that are used in a dozen of components throughout my app.

I want to create a decorator function to the axios instance object, that:

1. makes the request 2. if fail && error_code = 401, update user route to `/login` 3. if success, return promise 

The problem I have with the above is to update the route of the user. Previously, in react-router-v3, I could have imported the browserHistory object directly from the react-router package, which is no longer possible.

So, my question is, how can I access the history object outside of the React Component without passing it trough the call stack?

like image 343
Dragos Rizescu Avatar asked May 24 '17 08:05

Dragos Rizescu


People also ask

How do you access history outside the react component?

We would obviously want some additional logic in there, but the point is that we can access the history object through props , even though no props were passed to Login , and use history. push to push a new entry onto the history stack.

How do you get the history object in react?

Get History on react-routerWe can get the history with React Royer by calling the createBrowserHistory method. We can also use the withRouter higher-order component to inject the history object into a component. For instance, we can write: import { withRouter } from 'react-router-dom'; class App extends React.


2 Answers

react-router v4 also provides a way to share history via the history package, namely createBrowserHistory() function.

The important part is to make sure that the same history object is shared across your app. To do that you can take advantage of the fact that node modules are singletons.

Create a file called history.js in your project, with the following content:

import { createBrowserHistory } from 'history';  const history = createBrowserHistory(); export default history; 

You can then just import it in your application via:

import history from "./history.js"; 

Please note that only Router accepts the history prop (BrowserRouter does not), so be sure to update your router JSX accordingly:

import { Router } from "react-router-dom"; import history from "./history.js";  // and then in your JSX: return (   <Router history={history}>     {/* routes as usuall */}   </Router> ) 

A working example can be found at https://codesandbox.io/s/owQ8Wrk3

like image 160
BTMPL Avatar answered Sep 26 '22 08:09

BTMPL


Today, I faced the same issue. Maybe my solution helps somebody else.

src/axiosAuthenticated.js

import axios from 'axios'; import { createBrowserHistory } from 'history';   const UNAUTHORIZED = 401;  axios.interceptors.response.use(   response => response,   error => {     const {status} = error.response;     if (status === UNAUTHORIZED) {       createBrowserHistory().push('/');       window.location.reload();     }     return Promise.reject(error);  } );  export default axios; 

Also, if you want to intercept any request to add token stored in LocalStorage:

let user = JSON.parse(localStorage.getItem('user'));  var authToken = ""; if (user && user.token)   authToken = 'Bearer ' + user.token;  axios.defaults.headers.common = {'Authorization': `${authToken}`} 

To use it, instead of importing from 'axios', import from 'axiosAuthenticated' like this:

import axios from 'utils/axiosAuthenticated' 
like image 36
manna Avatar answered Sep 23 '22 08:09

manna