My solution was to do essentially what you describe. I made a HOC to wrap my route's component in if it requires that the user be logged in:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withRouter, Redirect } from 'react-router-dom';
/**
* Higher-order component (HOC) to wrap restricted pages
*/
export default function LoggedInOnly(BaseComponent) {
class Restricted extends Component {
state = {};
static getDerivedStateFromProps(nextProps) {
const { history, location } = nextProps;
if (!nextProps.isLoggedIn) {
history.replace({ pathname: '/signin', search: `dest=${encodeURIComponent(location.pathname)}` });
}
return null;
}
render() {
const { location, staticContext } = this.props;
if (this.props.isLoggedIn) return <BaseComponent {...this.props} />;
const destinationURL = `/signin?dest=${encodeURIComponent(location.pathname)}`;
if (staticContext) staticContext.url = destinationURL;
return <Redirect to={destinationURL} />;
}
}
const mapStateToProps = state => ({
isLoggedIn: !!state.globalUserState.loggedInUserEmail,
});
return withRouter(connect(mapStateToProps)(Restricted));
}
I also set the url on the static context in my case so I can handle redirects appropriately in server side rendering. If you're not doing the same you can ignore that part.
For using it, though, I redirect after my SSR render function, like so:
if (context.url) {
console.log(`Redirecting to URL ${context.url}`);
return res.redirect(context.url);
}
A route using this would look like:
<Route path="/preferences" component={LoggedInOnly(SettingsView)} />
On my login page I grab the url parameters to see if there's a destination. If there is, I redirect there on login success.
I do this using query-string and the search component of the location:
const { destination } = queryString.parse(props.location.search);
The above assumes you're using withRouter to get the location info in the props.
On authentication success in the client I simply redirect to destination if it exists:
window.location.href = this.props.destination;
You could also use history.push or similar to accomplish the above.
In my case, as you can see, I'm using redux to track the logged in user state.