React router v6 programmatically redirect - reactjs

I am in /customerOrders/13 page and from there I try to redirect to /customerOrders/14 using navigate('/customerOrders/14'). Even though the URL is updated, page is not redirected to /customerOrders/14.
Below are code fragments I extracted related to this from the codebase.
App.js
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
...
<BrowserRouter>
<Routes>
<Route path="customerOrders/:id" element={<CustomerOrderForm />}></Route>
</Routes>
<Router>
CustomerOrderForm.jsx
import { useNavigate } from "react-router-dom";
...
const CustomerOrderForm = () => {
let navigate = useNavigate();
const save = async () => {
//
// logic to persist data goes here...
//
navigate(`/customerOrders/${customerOrderId}`);
}
...
}

When you are on a given route:
<Route path="customerOrders/:id" element={<CustomerOrderForm />} />
and navigating to the same route already rendering the mounted component then the component needs to "listen" for changes to the route, in this case, specifically the id route match param that is updated. Use an useEffect hook with a dependency on the id route match param to rerun any logic depending on it.
import { useNavigate, useParams } from "react-router-dom";
...
const CustomerOrderForm = () => {
const navigate = useNavigate();
const { id } = useParams();
useEffect(() => {
// rerun logic depending on id value
}, [id]);
const save = async () => {
//
// logic to persist data goes here...
//
navigate(`/customerOrders/${customerOrderId}`);
};
...
};

Related

unable to redirect with this command navigate('/login?redirect=shipping') on react router dom i am using version 6

I am following a course in that course instructor wrote
react router dom version 5
const checkoutHandler = () => {
history.push('/login?redirect=shipping')
}
the above code is working fine in that course video,he is logging in and redirecting to shipping page
now i am using version 6 i changed above code to, i am unable to redirect to shipping
import {useNavigate} from 'react-router-dom';
const navigate=useNavigate();
const checkoutHandler=()=>{
navigate('/login?redirect=shipping')
}
and i can't understand what this '/login?navigate=shipping' command is doing exactly, why i am not able to rdirect.
MRE
App.js
<Routes>
<Route path='/cart' element={<CartScreen/>}/>
<Route path='/login' element={<LoginScreen/>}/>
<Route path='/shipping' element={<ShippingScreen/>}/>
<Route path='/' element={<HomeScreen/>} exact/>
</Routes>
CartScreen , Click on Checkout.
const checkoutHandler=()=>{
navigate('/login?navigate=shipping')
}
Takes you to Login page
Fill in Form Hit Login
login screen
const redirect = location.search ?
location.search.split('=')[1] : '/'
useEffect(() => {
if (localStorage.getItem('userInfo') !== null) {
navigate(redirect)
}
}, [])
isSuccess && navigate('/')
Issue
The issue is that react-router-dom#6 is capable of both absolute and relative path routing. The difference is that absolute paths start with a leading "/" character while relative paths do not.
The redirect target is "shipping" since the queryString is "?redirect=shipping"
navigate('/login?redirect=shipping');
In the LoginScreen component the code is accessing the location.searchand getting the"shipping"` value and attempting to navigate there.
const redirect = location.search ? location.search.split('=')[1] : '/'
useEffect(() => {
if (localStorage.getItem('userInfo') !== null) {
navigate(redirect); // <-- navigate("shipping")
}
}, []);
The result of this is a relative navigation from the current route path "/login" to "/login/shipping" since the leading "/" is missing.
Solution
Use the useSearchParams hook to access the queryString (instead of the "hackish" string manipulation), and navigate correctly to the "/shipping" route.
Example:
import { useNavigate, useSearchParams } from 'react-router-dom';
...
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const redirect = searchParams.get("redirect");
useEffect(() => {
if (JSON.parse(localStorage.getItem('userInfo'))) {
navigate(`/${redirect}`); // <-- navigate("/shipping")
}
}, [redirect]);

How can I redirect to previous page after login in react router?

I am looking to redirect to the page the user visited last after he/she finishes login, I am using react-router for this. How can I do that?
You can use query strings to accomplish this.
Add dependency query-string to your react app.
Whenever the user is trying to access a protected path, you have to redirect to the log-in screen if the user is not logged in yet. To do this you will do something like this.
history.push('/login');
But we can pass the previous as a query as follows. We can take the previous path using useLocation from react-router
const prevLocation = useLocation();
history.push(`/login?redirectTo=${prevLocation}`);
Now after successful login, we can get the query string that was passed in the previous path. We can set a default path if the previous path is null.
const handleSuccessLogin = () => {
const location = useLocation();
const { redirectTo } = queryString.parse(location.search);
history.push(redirectTo == null ? "/apps" : redirectTo);
};
This is IMO the best solution out there.
#Burhan's solution works well if /login is a simple login page without further redirects. In my scenario, the login page just checks the credentials in localStorage and further redirects to the IdP login page if credentials are unavailable or expired.
My solution using react-router-dom#6 and aws-amplify for Federated Login/SSO is demonstrated in the following code snippets. Note they are not complete or runnable but just explain how it works.
In App component use PrivateRoute (refer to react-router-dom#6 doc for details) to check if the login credentials are available (auth is provided via a separate AuthContext which is out of this topic):
const PrivateRoute: React.FC<{user: AuthenticatedUser}> = ({ user }) => {
const location = useLocation();
return user ? <Outlet /> : <Navigate to="/login" replace state={{ from: location }} />;
};
In the App component applies the PrivateRoute to /:
return (
<Routes>
<Route path="/" element={<PrivateRoute user={auth.user} />}>
... // Other routes
</Route>
<Route path="/login" element={<Login />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
In Login component before calls aws-amplify to start the federated login process, store the original URL into sessionStorage:
const login = async () => {
sessionStorage.setItem('beforeLogin', location.state?.from?.pathname);
await Auth.federatedSignIn();
};
In the federated login callback handler, get both the location state and url from sessionStorage and use whichever available after calling auth context to set the authenticated user:
Auth.currentAuthenticatedUser()
.then((currentUser) => {
if (currentUser) {
auth.setUser(currentUser);
const beforeLoginUrl = sessionStorage.getItem('beforeLogin');
sessionStorage.removeItem('beforeLogin');
navigate(beforeLoginUrl ?? location.state?.from ?? '/default');
}
})
.catch(console.error);
I need to check both as in my case if Login component finds valid credentials it would not redirect to IdP at all thus sessionStorage would not have the URL but only location.state?.from has.
I adapted #Bonttimo 's first solution to pass the entire location object in state, so that you can preserve eventual search queries in the original url.
The login button:
import { Link, useLocation } from "react-router-dom";
export const Navigation: FC = () => {
const location = useLocation();
return (
<Link to="/accounts/login" state={{ redirectTo: location }}>
<Button text="Login" />
</Link>
)
}
The same if you're using protected routes that redirect to the login page (based on this):
import React, { FC, useContext } from "react";
import { Navigate, Outlet, useLocation } from "react-router-dom";
import { UserContext } from "../contexts/user.context";
type Props = {
redirectPath?: string;
};
export const ProtectedRoute: FC<Props> = ({ redirectPath = "/accounts/login" }) => {
const location = useLocation();
const { currentUser } = useContext(UserContext);
if (!currentUser) {
return <Navigate to={redirectPath} replace state={{ redirectTo: location }} />;
}
return <Outlet />;
};
Then the Login page:
type RedirectLocationState = {
redirectTo: Location;
};
export const Login = () => {
const navigate = useNavigate();
const { state: locationState } = useLocation();
const onLogin = () => {
if (locationState) {
// state is any by default
const { redirectTo } = locationState as RedirectLocationState;
navigate(`${redirectTo.pathname}${redirectTo.search}`);
}
}
return (...)
}
This allows you to preserve the original url intact.
E.g. someone sent you a link to /users/list?country=13, but only authenticated users can see the users list page. This solution would redirect you to the login page and, upon logging in, it would take you back to /users/list?country=13.
There are two easy ways of doing this in React router v6, passing the previous location in the link state or just with the useNavigate hook.
First solution (Passing the previous location in the link state)
import { NavLink, useLocation } from "react-router-dom";
export default function App() {
const location = useLocation();
return (
<NavLink to="/login" state={{ prev: location.pathname }}>
Login
</NavLink>
);
}
then in the login component extracting the state
import { useNavigate, useLocation } from "react-router-dom";
export default function Login() {
const navigate = useNavigate();
const { state } = useLocation();
// Then when the user logs in you redirect them back with
const onLogin = () => navigate(state);
return (...)
};
Second solution (Using only the useNavigate hook)
import { useNavigate } from "react-router-dom";
export default function Login() {
const navigate = useNavigate();
// Then when the user logs in you redirect them back with the -1
// means go one page back in the history. you can also pass -2...
const onLogin = () => navigate(-1);
return (...)
};
if you use react-router-dom#6 flowed this step :
1 . Your protected Route
import { Navigate, Outlet,} from "react-router-dom";
const PrivateRouters = () => {
let userAuth = true ;
return (
userAuth ? <Outlet/> : <Navigate to="/login" />
)
}
export default PrivateRouters;
Login component use submit function useNavigate()
1st import :
import { useNavigate } from "react-router-dom";
2nd variable declear :
const navigate = useNavigate();
3rd: user submit function :
navigate("/pathname");

react-router-dom useHistory() not working

The useHistory() hook is not working in my project. I have it in different components but none of them work.
I am using "react-router-dom": "^5.2.0",
import {useHistory} from 'react-router-dom'
const history = useHistory()
const logout = () => {
toggleMenu()
setUser(null)
dispatch({type: 'LOGOUT'})
history.push('/')
}
And also in action its not working
export const signin = (formdata, history, setError) => async (dispatch) => {
try {
const {data} = await API.signIn(formdata)
if(data.error){
setError(data.message)
}else{
dispatch({type: SIGNIN, data})
history.push('/dashboard')
}
} catch (error) {
setError(error)
console.log(error)
}
}
Here is my router.js file
const Router = () => {
const user = JSON.parse(localStorage.getItem('profile'))
return (
<BrowserRouter>
<>
{user && <Navigation/>}
<Switch>
<Route path='/page-not-found' component={Auth}/>
<Route path='/' exact component={()=>((user && user.result) ? <Redirect to="/dasboard"/> : <Auth/>)} />
<Route path='/dashboard' component={() => (user ? <Dashboard/> : <Redirect to='/'/>)} />
<Route path='/books-purchase' component={() => (user ? <BooksPage/> : <Redirect to='/' />)} />
</Switch>
</>
</BrowserRouter>
)
}
For the version of react router dom less than 6.^
You can use useHistory() hook like your code is showing
For the latest version of react router dom greater than 6.^
You can use useNavigate() hook like this. You can also use without props
import { useNavigate } from 'react-router-dom';
class Login extends Component {
....
let navigate = useNavigate();
navigate('/');
.....
Instead of useHistory, try useNavigate:
import { useNavigate } from 'react-router-dom';
After some investigation, I found that there is a bug in react-router-dom version ^5.2.0. See this and this . I would suggest you to downgrade react-router-dom version to 4.10.1
In my point of view, It doesn't need to downgrade react-router-dom, just use "useNavigate" hook instead of "useHistory" hook. For example if you also want to send some data to your dashboard page, you can use it like so:
import { useNavigate } from 'react-router-dom'
const FunctionalComponent = () => {
const navigate = useNavigate();
const TestHandler = (someData) => {
navigate("/dashboard", {state: {someData: someData}});
//and if you don't want to send any data use like so:
//navigate("/dashboard");
}
}
Finally, if you want to use that sent data for example in your dashboard page, you can do it like so:
import { useLocation } from 'react-router-dom'
export const Dashboard = () => {
const location = useLocation();
useEffect(() => {
if (location.state.someData) {
// "someData" is available here.
}
});
You can refer to this migration guide: https://reactrouter.com/docs/en/v6/upgrading/v5
i have same error, I forgot add type to button that working function. when i give type,problem was solved
Sometimes, if we call history in dialog or modal it shows error, pass the method to components
const methodTopass= () => {
history.push("/route");
};
<componet methodTopass/>
left "react-router-dom": "^5.2.0", add "history": "4.10.1", in to package.json
then use import { createBrowserHistory } from "history";
and
let hist = createBrowserHistory();
hist.push("/domoy");

React lazy/Suspens + React Router dont change route until component is fetched

I am developing an application that uses the default React code spltting using the Lazy/Suspense approach and the React Router for component rendering. Currently, when I navigate to another path, if the network speed is slow, the path is updated and the fallback component is rendered while the component is fetched, is there any way to wait on the current path until the component package is completely downloaded?
Yes, in concurrent mode, where useTransition() is enabled, you can create a custom router to wrap each of the navigation methods on your history object in a suspense transition:
import { useState, unstable_useTransition as useTransition } from 'react';
import { Router } from 'react-router-dom';
const SuspenseRouter = ({ children, history, ...config }) => {
const [startTransition, isPending] = useTransition(config);
const [suspenseHistory] = useState(() => {
const { push, replace, go } = history;
history.push = (...args) => {
startTransition(() => { push.apply(history, args); });
};
history.replace = (...args) => {
startTransition(() => { replace.apply(history, args); });
};
history.go = (...args) => {
startTransition(() => { go.apply(history, args); });
};
});
suspenseHistory.isPending = isPending;
return (
<Router history={suspenseHistory}>
{children}
</Router>
);
};
export default SuspenseRouter;
Example usage might look something like this:
import { Suspense, lazy, unstable_createRoot as createRoot } from 'react';
import { Switch, Route } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import SuspenseRouter from './components/SuspenseRouter';
const history = createBrowserHistory();
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<SuspenseRouter history={history} timeoutMs={2000}>
<Suspense fallback="Loading...">
<Switch>
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
</SuspenseRouter>
);
createRoot(document.getElementById('root')).render(<App />);
Set timeoutMs to Infinity if you want to wait indefinitely on the previous route. In the example above, setting it to 2000 should wait on the previous route for up to 2 seconds, then display the fallback if the code for the requested route hasn't downloaded by then.
Here is another option: instead of suspending url change you can suspend screen change.
Package react-router-loading allows to show loading bar and fetch some data before switching the screen.
Just use Switch and Route from this package instead of react-router-dom:
import { Switch, Route } from "react-router-loading";
Add loading props to the Route where you want to wait something:
<Route path="/my-component" component={MyComponent} loading/>
And then somewhere at the end of fetch logic in MyComponent add loadingContext.done();:
import { LoadingContext } from "react-router-loading";
const loadingContext = useContext(LoadingContext);
const loading = async () => {
//fetching some data
//call method to indicate that fetching is done and we are ready to switch
loadingContext.done();
};

Detect Route Change with react-router

I have to implement some business logic depending on browsing history.
What I want to do is something like this:
reactRouter.onUrlChange(url => {
this.history.push(url);
});
Is there any way to receive a callback from react-router when the URL gets updated?
You can make use of history.listen() function when trying to detect the route change. Considering you are using react-router v4, wrap your component with withRouter HOC to get access to the history prop.
history.listen() returns an unlisten function. You'd use this to unregister from listening.
You can configure your routes like
index.js
ReactDOM.render(
<BrowserRouter>
<AppContainer>
<Route exact path="/" Component={...} />
<Route exact path="/Home" Component={...} />
</AppContainer>
</BrowserRouter>,
document.getElementById('root')
);
and then in AppContainer.js
class App extends Component {
componentWillMount() {
this.unlisten = this.props.history.listen((location, action) => {
console.log("on route change");
});
}
componentWillUnmount() {
this.unlisten();
}
render() {
return (
<div>{this.props.children}</div>
);
}
}
export default withRouter(App);
From the history docs:
You can listen for changes to the current location using
history.listen:
history.listen((location, action) => {
console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`)
console.log(`The last navigation action was ${action}`)
})
The location object implements a subset of the window.location
interface, including:
**location.pathname** - The path of the URL
**location.search** - The URL query string
**location.hash** - The URL hash fragment
Locations may also have the following properties:
location.state - Some extra state for this location that does not reside in the URL (supported in createBrowserHistory and
createMemoryHistory)
location.key - A unique string representing this location (supported
in createBrowserHistory and createMemoryHistory)
The action is one of PUSH, REPLACE, or POP depending on how the user
got to the current URL.
When you are using react-router v3 you can make use of history.listen() from history package as mentioned above or you can also make use browserHistory.listen()
You can configure and use your routes like
import {browserHistory} from 'react-router';
class App extends React.Component {
componentDidMount() {
this.unlisten = browserHistory.listen( location => {
console.log('route changes');
});
}
componentWillUnmount() {
this.unlisten();
}
render() {
return (
<Route path="/" onChange={yourHandler} component={AppContainer}>
<IndexRoute component={StaticContainer} />
<Route path="/a" component={ContainerA} />
<Route path="/b" component={ContainerB} />
</Route>
)
}
}
Update for React Router 5.1+.
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function SomeComponent() {
const location = useLocation();
useEffect(() => {
console.log('Location changed');
}, [location]);
...
}
react-router v6
In react-router v6, this can be done by combining the useLocation and useEffect hooks
import { useLocation } from 'react-router-dom';
const MyComponent = () => {
const location = useLocation()
React.useEffect(() => {
// runs on location, i.e. route, change
console.log('handle route change here', location)
}, [location])
...
}
For convenient reuse, you can do this in a custom useLocationChange hook
// runs action(location) on location, i.e. route, change
const useLocationChange = (action) => {
const location = useLocation()
React.useEffect(() => { action(location) }, [location])
}
const MyComponent1 = () => {
useLocationChange((location) => {
console.log('handle route change here', location)
})
...
}
const MyComponent2 = () => {
useLocationChange((location) => {
console.log('and also here', location)
})
...
}
If you also need to see the previous route on change, you can combine with a usePrevious hook
const usePrevious = (value) => {
const ref = React.useRef()
React.useEffect(() => { ref.current = value })
return ref.current
}
const useLocationChange = (action) => {
const location = useLocation()
const prevLocation = usePrevious(location)
React.useEffect(() => {
action(location, prevLocation)
}, [location])
}
const MyComponent1 = () => {
useLocationChange((location, prevLocation) => {
console.log('changed from', prevLocation, 'to', location)
})
...
}
It's important to note that all the above fire on the first client route being mounted, as well as subsequent changes. If that's a problem, use the latter example and check that a prevLocation exists before doing anything.
If you want to listen to the history object globally, you'll have to create it yourself and pass it to the Router. Then you can listen to it with its listen() method:
// Use Router from react-router, not BrowserRouter.
import { Router } from 'react-router';
// Create history object.
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
// Listen to history changes.
// You can unlisten by calling the constant (`unlisten()`).
const unlisten = history.listen((location, action) => {
console.log(action, location.pathname, location.state);
});
// Pass history to Router.
<Router history={history}>
...
</Router>
Even better if you create the history object as a module, so you can easily import it anywhere you may need it (e.g. import history from './history';
This is an old question and I don't quite understand the business need of listening for route changes to push a route change; seems roundabout.
BUT if you ended up here because all you wanted was to update the 'page_path' on a react-router route change for google analytics / global site tag / something similar, here's a hook you can now use. I wrote it based on the accepted answer:
useTracking.js
import { useEffect } from 'react'
import { useHistory } from 'react-router-dom'
export const useTracking = (trackingId) => {
const { listen } = useHistory()
useEffect(() => {
const unlisten = listen((location) => {
// if you pasted the google snippet on your index.html
// you've declared this function in the global
if (!window.gtag) return
window.gtag('config', trackingId, { page_path: location.pathname })
})
// remember, hooks that add listeners
// should have cleanup to remove them
return unlisten
}, [trackingId, listen])
}
You should use this hook once in your app, somewhere near the top but still inside a router. I have it on an App.js that looks like this:
App.js
import * as React from 'react'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import Home from './Home/Home'
import About from './About/About'
// this is the file above
import { useTracking } from './useTracking'
export const App = () => {
useTracking('UA-USE-YOURS-HERE')
return (
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
)
}
// I find it handy to have a named export of the App
// and then the default export which wraps it with
// all the providers I need.
// Mostly for testing purposes, but in this case,
// it allows us to use the hook above,
// since you may only use it when inside a Router
export default () => (
<BrowserRouter>
<App />
</BrowserRouter>
)
I came across this question as I was attempting to focus the ChromeVox screen reader to the top of the "screen" after navigating to a new screen in a React single page app. Basically trying to emulate what would happen if this page was loaded by following a link to a new server-rendered web page.
This solution doesn't require any listeners, it uses withRouter() and the componentDidUpdate() lifecycle method to trigger a click to focus ChromeVox on the desired element when navigating to a new url path.
Implementation
I created a "Screen" component which is wrapped around the react-router switch tag which contains all the apps screens.
<Screen>
<Switch>
... add <Route> for each screen here...
</Switch>
</Screen>
Screen.tsx Component
Note: This component uses React + TypeScript
import React from 'react'
import { RouteComponentProps, withRouter } from 'react-router'
class Screen extends React.Component<RouteComponentProps> {
public screen = React.createRef<HTMLDivElement>()
public componentDidUpdate = (prevProps: RouteComponentProps) => {
if (this.props.location.pathname !== prevProps.location.pathname) {
// Hack: setTimeout delays click until end of current
// event loop to ensure new screen has mounted.
window.setTimeout(() => {
this.screen.current!.click()
}, 0)
}
}
public render() {
return <div ref={this.screen}>{this.props.children}</div>
}
}
export default withRouter(Screen)
I had tried using focus() instead of click(), but click causes ChromeVox to stop reading whatever it is currently reading and start again where I tell it to start.
Advanced note: In this solution, the navigation <nav> which inside the Screen component and rendered after the <main> content is visually positioned above the main using css order: -1;. So in pseudo code:
<Screen style={{ display: 'flex' }}>
<main>
<nav style={{ order: -1 }}>
<Screen>
If you have any thoughts, comments, or tips about this solution, please add a comment.
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Sidebar from './Sidebar';
import Chat from './Chat';
<Router>
<Sidebar />
<Switch>
<Route path="/rooms/:roomId" component={Chat}>
</Route>
</Switch>
</Router>
import { useHistory } from 'react-router-dom';
function SidebarChat(props) {
**const history = useHistory();**
var openChat = function (id) {
**//To navigate**
history.push("/rooms/" + id);
}
}
**//To Detect the navigation change or param change**
import { useParams } from 'react-router-dom';
function Chat(props) {
var { roomId } = useParams();
var roomId = props.match.params.roomId;
useEffect(() => {
//Detect the paramter change
}, [roomId])
useEffect(() => {
//Detect the location/url change
}, [location])
}
Use the useLocation() Hook to detect the URL change and put it in dependency array in useEffect() this trick worked for me
const App = () => {
const location = useLocation();
useEffect(() => {
window.scroll(0,0);
}, [location]);
return (
<React.Fragment>
<Routes>
<Route path={"/"} element={<Template/>} >
<Route index={true} element={<Home/>} />
<Route path={"cart"} element={<Cart/>} />
<Route path={"signin"} element={<Signin/>} />
<Route path={"signup"} element={<Signup/>} />
<Route path={"product/:slug"} element={<Product/>} />
<Route path={"category/:category"} element={<ProductList/>} />
</Route>
</Routes>
</React.Fragment>
);
}
export default App;
You can use the useLocation with componentDidUpdate for getting the route change for class component and useEffect for functional component
In Class component
import { useLocation } from "react-router";
class MainApp extends React.Component {
constructor(props) {
super(props);
}
async componentDidUpdate(prevProps) {
if(this.props.location.pathname !== prevProps.location.pathname)
{
//route has been changed. do something here
}
}
}
function App() {
const location = useLocation()
return <MainApp location={location} />
}
In functional component
function App() {
const location = useLocation()
useEffect(() => {
//route change detected. do something here
}, [location]) //add location in dependency. It detects the location change
return <Routes>
<Route path={"/"} element={<Home/>} >
<Route path={"login"} element={<Login/>} />
</Routes>
}
React Router V5
If you want the pathName as a string ('/' or 'users'), you can use the following:
// React Hooks: React Router DOM
let history = useHistory();
const location = useLocation();
const pathName = location.pathname;

Resources