With react-router
I can use the Link
element to create links which are natively handled by react router.
I see internally it calls t
With the current React version (15.3), this.props.history.push('/location');
worked for me, but it showed the following warning:
browser.js:49 Warning: [react-router]
props.history
andcontext.history
are deprecated. Please usecontext.router
.
and I solved it using context.router
like this:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.backPressed = this.backPressed.bind(this);
}
backPressed() {
this.context.router.push('/back-location');
}
...
}
MyComponent.contextTypes = {
router: React.PropTypes.object.isRequired
};
export default MyComponent;
Update : React Router v6 with hooks
import {useNavigate} from 'react-router-dom';
let navigate = useNavigate();
navigate('home');
And to move across the browser history,
navigate(-1); ---> Go back
navigate(1); ---> Go forward
navigate(-2); ---> Move two steps backward.
with React-Router v4 on the horizon, there is now a new way of doing this.
import { MemoryRouter, BrowserRouter } from 'react-router';
const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;
<Router location="/page-to-go-to"/>
react-lego is an example app that shows how to use/update react-router and it includes example functional tests which navigate the app.
Maybe not the best solution but it gets the job done:
import { Link } from 'react-router-dom';
// create functional component Post
export default Post = () => (
<div className="component post">
<button className="button delete-post" onClick={() => {
// ... delete post
// then redirect, without page reload, by triggering a hidden Link
document.querySelector('.trigger.go-home').click();
}}>Delete Post</button>
<Link to="/" className="trigger go-home hidden"></Link>
</div>
);
Basically, a logic tied to one action (in this case a post deletion) will end up calling a trigger for redirect. This is not ideal because you will add a DOM node 'trigger' to your markup just so you can conveniently call it when needed. Also, you will directly interact with the DOM, which in a React component may not be desired.
Still, this type of redirect is not required that often. So one or two extra, hidden links in your component markup would not hurt that much, especially if you give them meaningful names.
This worked for me, no special imports needed:
<input
type="button"
name="back"
id="back"
class="btn btn-primary"
value="Back"
onClick={() => { this.props.history.goBack() }}
/>
So in my answer there are 3 different ways to redirect programmatically to a route. Some of the solutions has been presented already but the following ones focused only for functional components with an additional demo application.
Using the following versions:
react: 16.13.1
react-dom: 16.13.1
react-router: 5.2.0
react-router-dom: 5.2.0
typescript: 3.7.2
Configuration:
So first of all the solution is using HashRouter
, configured as follows:
<HashRouter>
// ... buttons for redirect
<Switch>
<Route exact path="/(|home)" children={Home} />
<Route exact path="/usehistory" children={UseHistoryResult} />
<Route exact path="/withrouter" children={WithRouterResult} />
<Route exact path="/redirectpush" children={RedirectPushResult} />
<Route children={Home} />
</Switch>
</HashRouter>
From the documentation about <HashRouter>
:
A
<Router>
that uses the hash portion of the URL (i.e.window.location.hash
) to keep your UI in sync with the URL.
Solutions:
<Redirect>
to push using useState
:Using in a functional component (RedirectPushAction component from my repository) we can use useState to handle redirect. Tricky part is once the redirection happened we need to set the redirect
state back to false
. By using setTimeOut
with 0
delay we are waiting until React commits Redirect
to the DOM then getting back the button in order to use next time.
Please find my example below:
const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
let render = null;
if (redirect) {
render = <Redirect to="/redirectpush" push={true} />
// in order wait until commiting to the DOM
// and get back the button for clicking next time
setTimeout(() => setRedirect(false), 0);
}
return render;
}, [redirect]);
return <>
{handleRedirect()}
<button onClick={() => setRedirect(true)}>
Redirect push
</button>
</>
From <Redirect> documentation:
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 (HTTP 3xx) do.
useHistory
hook:In my solution there is a component called UseHistoryAction which represents the following:
let history = useHistory();
return <button onClick={() => { history.push('/usehistory') }}>
useHistory redirect
</button>
The
useHistory
hook gives us access to the history object which helps us programmatically navigate or change routes.
withRouter
, get the history
from props
:Created one component called WithRouterAction, displays as below:
const WithRouterAction = (props:any) => {
const { history } = props;
return <button onClick={() => { history.push('/withrouter') }}>
withRouter redirect
</button>
}
export default withRouter(WithRouterAction);
Reading from withRouter documentation:
You can get access to the
history
object's properties and the closest<Route>
's match via thewithRouter
higher-order component.withRouter
will pass updatedmatch
,location
, andhistory
props to the wrapped component whenever it renders.
Demo:
For better representation I have built a GitHub repository with these examples, please find it below:
https://github.com/norbitrial/react-router-programmatically-redirect-examples
I hope this helps!