I have slightly adjusted the React Router example for the private routes to play nice with Redux, but no components are rendered when Linking or Redirecting to other \'pages
Set the private route to not be pure:
export default connect(mapStateToProps, null, null, {
pure: false,
})(PrivateRoute);
This will let the Component re-render.
Please see: react-router-4-x-privateroute-not-working-after-connecting-to-redux.
Just had same problem, I solved it by making my App redux container and passing isAuthenticated as a prop to PrivateRoute
Here it is, I hope it helps
const App = (props) => {
return (
<Provider store={store}>
<Router>
<div>
<PrivateRoute path="/secured" component={Secured} isAuthenticated={props.isAuthenticated} />
</div>
</Router>
</Provider>
);
};
const mapStateToProps = state => ({
isAuthenticated: state.isAuthenticated
});
export default connect(mapStateToProps)(App);
Then in my PrivateRoute
const PrivateRoute = ({ component: Component, isAuthenticated, ...rest}) => (
<Route
{...rest}
render={props => (
isAuthenticated
? (
<Component {...props} />
)
: (<Redirect to={{ pathname: '/login', state: { from: props.location} }} />)
)}
/>
);
export default PrivateRoute;
According to react-router documentation you may just wrap your connect
function with withRouter
:
// before
export default connect(mapStateToProps)(Something)
// after
import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(Something))
This worked for me and my views started to be updated along with routes in this case.
I have the similar issue like @Rein. In my case, PrivateRoute looks almost same to the original version but only connected to Redux and used it instead of fakeAuth in the original example.
const PrivateRoute = ({ component: Component, auth, ...rest }) => (
<Route
{...rest}
render={props =>
auth.isAuthenticated
? <Component {...props} />
: <Redirect to={{ pathname: "/login" }} />}
/>
);
PrivateRoute.propTypes = {
auth: PropTypes.object.isRequired,
component: PropTypes.func.isRequired
}
const mapStateToProps = (state, ownProps) => {
return {
auth: state.auth
}
};
export default connect(mapStateToProps)(PrivateRoute);
Usage and result:-
<PrivateRoute path="/member" component={MemberPage} />
<PrivateRoute path="/member" component={MemberPage} auth={auth} />
<PrivateRoute path="/member" component={MemberPage} anyprop={{a:1}} />
You need to wrap your Route
with <Switch>
tag
ReactDOM.render(
<Provider store={store}>
<App>
<Router>
<div>
<Switch>
<PrivateRoute exact path="/"><Home /></PrivateRoute>
// ... other private routes
<Route path="/login" component={Login} />
</Switch>
</div>
</Router>
</App>
</Provider>,
document.getElementById('root'));
I have struggled with this issue as well, and here is my solution.
Instead of passing isAuthenticated to every < PrivateRoute> component, you just need to get isAuthenticated from state in < PrivateRoute> itself.
import React from 'react';
import {Route, Redirect, withRouter} from 'react-router-dom';
import {connect} from 'react-redux';
// isAuthenticated is passed as prop here
const PrivateRoute = ({component: Component, isAuthenticated , ...rest}) => {
return <Route
{...rest}
render={
props => {
return isAuthenticated ?
(
<Component {...props} />
)
:
(
<Redirect
to={{
pathname: "/login",
state: {from: props.location}
}}
/>
)
}
}
/>
};
const mapStateToProps = state => (
{
// isAuthenticated value is get from here
isAuthenticated : state.auth.isAuthenticated
}
);
export default withRouter(connect(
mapStateToProps, null, null, {pure: false}
)(PrivateRoute));