Want to trigger an alert or console log before the user navigates to a new domain. From the docs, setRouteLeaveHook or onLeave should work. I followed these directions.
import React from 'react'
import { withRouter } from 'react-router'
const Page = withRouter(
React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave)
},
routerWillLeave(nextLocation) {
console.log("Moved to different domain");
return 'Your work is not saved! Are you sure you want to leave?'
},
render() {
return Redirect
}
})
)
export default Page
Page is the top level component in my app. Using react-router v3 with redux.
How can I trigger an alert before the user leaves our site?
Add the withRouter HOC wrapper on your export like this:
export default withRouter(Page);
Related
We have implemented our application navigation using react-router.
Is there any way to block user navigation(including forward,backward buttons) with out any prompt in react.
react-router history block subscribe function i can't use as it will throw default prompt. In my case i want to show my custom dialog.
You can add an event listener popState to freeze the navigation.
Working demo
const Home = ({ history }) => {
useEffect(() => {
const browserNavigationHandle = () =>
window.history.pushState(null, null, document.URL);
window.history.pushState(null, null, document.URL);
window.addEventListener("popstate", browserNavigationHandle);
return () =>
window.removeEventListener("popstate", browserNavigationHandle);
}, []);
return <div>Home</div>;
};
export default Home;
There is no way to block a users browser navigation, as that would take away all control of a user and could be used in a very malicious way. What you can do though is stop your application from changing.
One way could be to listen to history changes and navigate back to the page the user should be on. Problem with that is will re-render and you might lose states, depending on your application.
Another way could be (as I havent tried this before) to use a customized history object. Check out how to setup the Router with history. As seen in their example:
import React from "react";
import ReactDOM from "react-dom";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
node
);
There might be a way to customize that history object so you can control its change and the applications response.
To disable back button you can do below code in higher order component
componentDidMount() {
const { history } = this.props;
window.addEventListener("popstate", () => {
history.go(1);
});
}
but this component must be a Route component
Just add useHistory().go(1) working for me.
use this to prevent routing
window.addEventListener('beforeunload', (event) => {
event.preventDefault();
event.stopPropagation();}
I am trying to navigate using history push inside App.jsx.
I have used below code for the same.
componentDidMount() {
if(!this.authService.isAuthenticated())
{
this.props.history.push('/Login');
}
}
But it is giving an error as history is undefined.
I tried logging props object and I got the below output.
Please help me in navigating inside app.jsx.
Export your component with withRouter.
import withRouter.
import { withRouter } from 'react-router'
Export in your component like this.
export default withRouter(MyComponent)//your component name
Dispatching the push action which was defined in mergeProps parameter of the react-redux connect() dispatches redux action but does not trigger url page change. I also wrapped the withRouter around the redux container but no seems to help.
//connect.js
import { Component } from './Component';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { push } from 'connected-react-router';
import { onFetch, onUpdate } from '../action-creators';
export default withRouter(connect(state => state,
{
onFetch,
onUpdate,
push
},
( state, actions ) => ({
...state,
onFetch: actions.onFetch,
onUpdate: index => {
actions.onUpdate( index );
actions.push( `/${ index }` );
}
})
)( Component ));
What can I do to also trigger actual page update along with the LOCATION_CNANGE redux action using the create-react-router package? At this point, only the connected-react-router middleware and the redux store are being updated but no actual page change.
Fixed it by modifying a redirect 'from' prop.
Root cause: a redirect was placed at the end of the switch child routes list as a catchall rerouting to the main page. However, all requests (including valid ones except '/') went to the catchall redirect and were rerouted to main page.
I need to detect if a route change has occurred so that I can change a variable to true.
I've looked through these questions:
1. https://github.com/ReactTraining/react-router/issues/3554
2. How to listen to route changes in react router v4?
3. Detect Route Change with react-router
None of them have worked for me. Is there a clear way to call a function when a route change occurs.
One way is to use the withRouter higher-order component.
Live demo (click the hyperlinks to change routes and view the results in the displayed console)
You can get access to the history object's properties and the closest 's match via the withRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/withRouter.md
import {withRouter} from 'react-router-dom';
class App extends Component {
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
console.log('Route change!');
}
}
render() {
return (
<div className="App">
...routes
</div>
);
}
}
export default withRouter(props => <App {...props}/>);
Another example that uses url params:
If you were changing profile routes from /profile/20 to /profile/32
And your route was defined as /profile/:userId
componentDidUpdate(prevProps) {
if (this.props.match.params.userId !== prevProps.match.params.userId) {
console.log('Route change!');
}
}
With React Hooks, it should be as simple as:
useEffect(() => {
const { pathname } = location;
console.log('New path:', pathname);
}, [location.pathname]);
By passing location.pathname in the second array argument, means you are saying to useEffect to only re-run if location.pathname changes.
Live example with code source: https://codesandbox.io/s/detect-route-path-changes-with-react-hooks-dt16i
React Router v5 now detects the route changes automatically thanks to hooks. Here's the example from the team behind it:
import { Switch, useLocation } from 'react-router'
function usePageViews() {
let location = useLocation()
useEffect(
() => {
ga.send(['pageview', location.pathname])
},
[location]
)
}
function App() {
usePageViews()
return <Switch>{/* your routes here */}</Switch>
}
This example sends a "page view" to Google Analytics (ga) every time the URL changes.
When component is specified as <Route>'s component property, React Router 4 (RR4) passes to it few additional properties: match, location and history.
Then u should use componentDidUpdate lifecycle method to compare location objects before and after update (remember ES object comparison rules). Since location objects are immutable, they will never match. Even if u navigate to the same location.
componentDidUpdate(newProps) {
if (this.props.location !== newProps.location) {
this.handleNavigation();
}
}
withRouter should be used when you need to access these properties within an arbitrary component that is not specified as a component property of any Route. Make sure to wrap your app in <BrowserRouter> since it provides all the necessary API, otherwise these methods will only work in components contained within <BrowserRouter>.
There are cases when user decides to reload the page via navigation buttons instead of dedicated interface in browsers. But comparisons like this:
this.props.location.pathname !== prevProps.location.pathname
will make it impossible.
How about tracking the length of the history object in your application state? The history object provided by react-router increases in length each time a new route is traversed. See image below.
ComponentDidMount and ComponentWillUnMount check:
React use Component-Based Architecture. So, why don't we obey this rule?
You can see DEMO.
Each page must be wrapped by an HOC, this will detect changing of page automatically.
Home
import React from "react";
import { NavLink } from "react-router-dom";
import withBase from "./withBase";
const Home = () => (
<div>
<p>Welcome Home!!!</p>
<NavLink to="/login">Go to login page</NavLink>
</div>
);
export default withBase(Home);
withBase HOC
import React from "react";
export default WrappedComponent =>
class extends React.Component {
componentDidMount() {
this.props.handleChangePage();
}
render() {
return <WrappedComponent />;
}
};
I wanted to build a Facebook login into my react/react-router/flux application.
I have a listener registered on the login event and would like to redirect the user to '/dashboard' if they are logged in. How can I do that? location.push didn't work very well, except after reloading the page completely.
React Router v3
This is what I do
var Router = require('react-router');
Router.browserHistory.push('/somepath');
React Router v4
Now we can use the <Redirect>component in React Router v4.
Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects.
import React, { Component } from 'react';
import { Redirect } from 'react-router';
export default class LoginComponent extends Component {
render(){
if(this.state.isLoggedIn === true){
return (<Redirect to="/your/redirect/page" />);
}else{
return (<div>Login Please</div>);
}
}
}
Documentation https://reacttraining.com/react-router/web/api/Redirect
React Router v0.13
The Router instance returned from Router.create can be passed around (or, if inside a React component, you can get it from the context object), and contains methods like transitionTo that you can use to transition to a new route.
React Router v2
Even though the question is already answered, I think it's relevant to post the solution that worked for me, since it wasn't covered in any of the solutions given here.
First, I'm using the router context on my LoginForm component
LoginForm.contextTypes = {
router: React.PropTypes.object
};
After that, I can access the router object inside my LoginForm component
handleLogin() {
this.context.router.push('/anotherroute');
}
PS: working on React-router version 2.6.0
React Router v3
Navigating Outside of Components
create your app with Router like this
// Your main file that renders a <Router>:
import { Router, browserHistory } from 'react-router'
import routes from './app/routes'
render(
<Router history={browserHistory} routes={routes} />,
mountNode
)
Somewhere like a Redux middleware or Flux action:
import { browserHistory } from 'react-router'
// Go to /some/path.
browserHistory.push('/some/path')
// Go back to previous location.
browserHistory.goBack()
react-router/tree/v3/docs
React Router v4.2.0
I am using React-16.2.0 & React-router-4.2.0
And I get solution by this code
this.props.history.push("/");
My working code:
.then(response => response.json())
.then(data => {
if(data.status == 200){
this.props.history.push("/");
console.log('Successfully Login');
}
})
I was following this document redirect-on-login-and-logout
I was also try by return <Redirect to='/' /> But unlucky, this not working for me.
React router v5 using hooks
These steps are for authorisation redirect. But can be used for login/logout redirection also.
The <Redirect/> accepts to prop as a string or an object. We can utilise the object to pass the redirection path after login/logout using hooks easily.
Get the pathname of url from where the <Redirect/> is called using
useLocation()
const {pathname} = useLocation()
In the to prop of <Redirect/> pass in the following object:
<Redirect to={{pathname:'/login',state: {referrer: pathname}}/>
In the Login component access the route state variable using useLocation() hook and use the useHistory() hook to redirect after successful login.
const history = useHistory();
const location = useLocation();
const login() => {
// After login success
const {state: {referrer}} = location;
history.push(referrer)
};
Check the official docs here
React Router v3
Navigating inside components
You should use withRouter decorator when it's necessary to redirect inside a component. The decorator uses context instead of you.
import {withRouter} from 'react-router'
fucntion Foo(props) {
props.router.push('/users/16');
}
export default withRouter(Foo);
withRouter(Component, [options])
A HoC (higher-order component) that wraps another component to enhance
its props with router props.
withRouterProps = {
...componentProps,
router,
params,
location,
routes
}
Pass in your component and it will return the
wrapped component.
You can explicit specify router as a prop to the wrapper component to
override the router object from context.
In your store:
data.router.transitionTo('user');
And router has:
"Route name="user" handler={User}"
User is route handler