React Router switched to component based routing starting with the version 4.
Redirects are now done by rendering a Redirect
component,
like this:Please note that you can use included withRouter
decorator but it can cause update blocking and introduce side effects.
This is small subset of it.
<Redirect to='/redirect-url-here' />
What I usually do is to keep redirectTo
property in component's state.
To redirect, I set it to the URL I want to redirect to,
and render Redirect
at the start of the render
method:
render() {
const { redirectTo } = this.state;
if (redirectTo) {
return <Redirect push to={ redirectTo } />;
}
return (
<YourComponentHere />
);
}
This approach works well, but I got tired of repeating the same code over and over again. So I pulled the functionality to a decorator (higher order component if you prefer).
Redirect decorator #
I did exactly what I described above, and exposed redirectTo
method
to a composed component.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
const withRedirect = ComposedComponent => class RedirectDecorator extends Component {
state = {
push: false,
redirectUrl: null,
}
componentDidUpdate(prevProps, prevState) {
const {
redirectUrl,
} = this.state;
// If component is rendered on redirect page as well
// (i.e. header or footer) it would cause redirect-loop
// as "<Redirect />" is being rendered every time.
// So we are resetting the state after redirect
if (!prevState.redirectUrl && redirectUrl) {
this.setState({
push: false,
redirectUrl: null,
});
}
}
redirectTo = (redirectUrl, push = false) => {
this.setState({
push,
redirectUrl,
});
}
render() {
const {
push,
redirectUrl,
} = this.state;
if (redirectUrl) {
return <Redirect push={ push } to={ redirectUrl } />;
}
return (
<ComposedComponent
{ ...this.props }
redirectTo={ this.redirectTo }
/>
);
}
};
export default withRedirect;
Usage #
Import newly added decorator and apply it to your component.
It will inject redirectTo
to it's props,
and you can use it anywhere to redirect user to a new URL.
import React, { Component } from 'react';
import withRedirect from 'path/to/redirect/decorator';
@withRedirect
export default class Example extends Component {
handleClick = () => {
const {
redirectTo,
} = this.props;
redirectTo('/', true);
}
render() {
return (
<button onClick={ this.handleClick }>
Take me home!
</button>
);
}
}
First parameter is obviously a URL, and the second one is boolean push
.
It is false
by default and in that case redirect URL will replace the current URL
(user won't be able to get back to it by clicking browser back button).
When set to true
it will push new URL to the history, leaving the old one as well.
Happy redirecting!