I am trying to make a PrivateRoute component for react. Here is my higher order component. Can you tell me what is the problem with this.
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
export default ({ component: Component, ...rest }) => {
class PrivateRoute extends React.Component {
render() {
console.log("This is private route called");
if (this.props.profile) {
return (
<Route
{...rest}
render={props =>
this.props.profile.loggedIn === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
}
}
}
const mapStateToProps = state => ({
profile: state.profile
});
return connect(mapStateToProps)(PrivateRoute);
};
Here's how you can accomplish a protected route via a protected route component.
Working example: https://codesandbox.io/s/yqo75n896x
containers/RequireAuth.js
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";
const RequireAuth = ({ match: { path }, isAuthenticated }) =>
!isAuthenticated ? (
<Redirect to="/signin" />
) : (
<div>
<Route exact path={`${path}/roster`} component={ShowPlayerRoster} />
<Route path={`${path}/roster/:id`} component={ShowPlayerStats} />
<Route path={`${path}/schedule`} component={Schedule} />
</div>
);
export default connect(state => ({
isAuthenticated: state.auth.isAuthenticated
}))(RequireAuth);
routes/index.js
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import Home from "../components/Home";
import Header from "../containers/Header";
import Info from "../components/Info";
import Sponsors from "../components/Sponsors";
import Signin from "../containers/Signin";
import RequireAuth from "../containers/RequireAuth";
import rootReducer from "../reducers";
const store = createStore(rootReducer);
export default () => (
<Provider store={store}>
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/info" component={Info} />
<Route path="/sponsors" component={Sponsors} />
<Route path="/protected" component={RequireAuth} />
<Route path="/signin" component={Signin} />
</Switch>
</div>
</BrowserRouter>
</Provider>
);
Or, if you want something that wraps all routes (instead of having to specify a protected route component). Then you can do something like the below.
Working example: https://codesandbox.io/s/5m2690nn6n
components/RequireAuth.js
import React, { Component, Fragment } from "react";
import { withRouter } from "react-router-dom";
import Login from "./Login";
import Header from "./Header";
class RequireAuth extends Component {
state = { isAuthenticated: false };
componentDidMount = () => {
if (!this.state.isAuthenticated) {
this.props.history.push("/");
}
};
componentDidUpdate = (prevProps, prevState) => {
if (
this.props.location.pathname !== prevProps.location.pathname &&
!this.state.isAuthenticated
) {
this.props.history.push("/");
}
};
isAuthed = () => this.setState({ isAuthenticated: true });
unAuth = () => this.setState({ isAuthenticated: false });
render = () =>
!this.state.isAuthenticated ? (
<Login isAuthed={this.isAuthed} />
) : (
<Fragment>
<Header unAuth={this.unAuth} />
{this.props.children}
</Fragment>
);
}
export default withRouter(RequireAuth);
routes/index.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Home from "../components/Home";
import Players from "../components/Players";
import Schedule from "../components/Schedule";
import RequireAuth from "../components/RequireAuth";
export default () => (
<BrowserRouter>
<RequireAuth>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/players" component={Players} />
<Route path="/schedule" component={Schedule} />
</Switch>
</RequireAuth>
</BrowserRouter>
);
Or, if you want something a bit more modular, where you can pick and choose any route, then you can create a wrapper HOC. See this example (while it's written for v3 and not for authentication, it's still the same concept).
It looks like your render function's only return is inside of an if block, so its returning null. You need to fix the logic to just return the Route and make profile a required prop in your proptypes check instead of using an if block.
PrivateRoute.propTypes = {
profile: PropTypes.object.isRequired
};
Related
After adding PublicRoute and PrivateRoute my app not working popup login and signup. It displaying a blank screen. Before adding PublicRoute and PrivateRoute, my app working fine with Route.
The App has an initial home page when I click on the Merchant button it should popup for the login page. Please find the below screenshot.
But it displays with a blank screen. Please find below screenshot
Please help me to fix this issue.
AppRouter.js
import React from 'react';
import {Router, Route , Switch} from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import { HomePage } from '../components/HomePage';
import DashboardPage from '../components/DashboardPage';
import StartLogin from '../components/StartLogin';
import { UserForm } from '../components/UserForm';
import PublicRoute from './PublicRouter';
import PrivateRoute from './PrivateRouter';
export const history = createHistory()
const AppRouter = () => (
<Router history={history}>
<div>
<Switch>
<PublicRoute path="/" component={HomePage} exact={true}/>
<PrivateRoute path="/dashboard" component={DashboardPage} />
</Switch>
</div>
</Router>
);
export default AppRouter;
PublicRoute.js
import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';
export const PublicRoute = ( {
isAuthenticated,
component: Component,
...rest}) => (
<Route {...rest} component={(props) => (
isAuthenticated ? (
<div>
<Redirect to='/dashboard' />
</div>
) : (
<Component {...props} />
)
)}/>
);
const mapStateToProps = (state) => ({
isAuthenticated: state.auth.merchLogin
})
export default connect(mapStateToProps)(PublicRoute);
PrivateRoute.js
import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';
import { HomePage } from '../components/HomePage';
export const PrivateRoute = ( {
isAuthenticated,
component: Component,
...rest}) => (
<Route {...rest} component={(props) => (
isAuthenticated ? (
<div>
<HomePage />
<Component {...props} />
</div>
) : (
<Redirect to='/' />
)
)}/>
);
const mapStateToProps = (state) => ({
isAuthenticated: state.auth.merchLogin
})
export default connect(mapStateToProps)(PrivateRoute);
Remove isAuthenticated from PublicRoute.js
<Route path="/" component={HomePage} exact={true}/>
I've got react-redux private router not working.
It is just showing me a blank page of the route I am trying to access.
And my states are not loading at Redux Dev Tools.
Can it also be the problem of HashRouter?
My PrivateRoute Component:
import React from "react";
import { connect } from "react-redux";
import {Router, Redirect, withRouter } from "react-router-dom";
import PropTypes from 'prop-types';
class PrivateRoute extends React.Component {
static propTypes = {
isAuthenticated: PropTypes.bool,
}
isLoggedin = () => {
return this.props.isAuthenticated;
};
render = () => {
let { component: Component, ...rest } = this.props;
return (
<Router
{...rest}
render={(props) =>
this.isLoggedin() ? (
<Component {...props} />
) : props.location.pathname === "/" ? null : (
<Redirect to="/" />
)
}
/>
);
};
}
const mapStateToProps = (state) => ({
auth: state.auth,
isAuthenticated: state.auth.isAuthenticated
})
export default withRouter(connect(mapStateToProps, null)(PrivateRoute));
My App where I am wrapping my Routes to make it private:
import {Provider} from 'react-redux';
import store from './store'
import {loadUser} from './actions/authActions'
import PrivateRoute from './components/auth/PrivateRoute'
class App extends React.Component {
componentDidMount(){
store.dispatch(loadUser())
}
render(){
return (
<Provider store={store}>
<HashRouter basename="/">
<Navbar />
<Route exact path="/" component={Home}/>
<PrivateRoute path="/aeons" component={AeonsList} />
<PrivateRoute path="/carrefours" component={CarrefoursList} />
<PrivateRoute path="/farmers" component={FarmersList} />
<PrivateRoute path="/foodhalls" component={FoodhallsList} />
<PrivateRoute path="/grands" component={GrandsList} />
<PrivateRoute path="/heros" component={HerosList} />
<PrivateRoute path="/primos" component={PrimosList} />
<PrivateRoute path="/ranchos" component={RanchsList} />
</HashRouter>
</Provider>
)
}
}
export default App;
You need to import Route, not Router when defining your privateRoute component.
import {Route } from "react-router-dom";
Check this
I'm trying to redirect user to /login if he isn't authenticated.
To do so, I'm checking if the user is authenticated in componentDidMount() and if he isn't I'm redirecting him to /login using the <Redirect to="/login"/> balise.
The problem is that I have this error: You should not use <Redirect> outside a <Router>, despite the fact that I am in a <BrowserRouter>
Here is my App.js
import React from 'react';
import {BrowserRouter, Route, Switch} from "react-router-dom";
import MainPage from "./pages/main-page/main-page";
import LoginPage from "./pages/login-page/login-page";
import PrivateRoute from "./components/private-route";
function App() {
return (
<BrowserRouter>
<Switch>
<PrivateRoute exact path="/" component={MainPage}/>
<Route path="/login" component={LoginPage}/>
</Switch>
</BrowserRouter>
);
}
export default App;
Here is my main-page.js
import React from 'react';
import authManager from "../../services/auth";
import Redirect from "react-router/modules/Redirect";
export default class MainPage extends React.Component{
state = {
loggedIn: false,
};
componentDidMount() {
authManager.isAuthenticate((res) => {
if (res.data)
this.setState({loggedIn: true})
}).then()
}
render() {
if (!this.state.loggedIn)
return <Redirect to='/login'/>;
return (
<div>
</div>
)
}
}
And here is my private-route.js
import { Route, Redirect } from 'react-router-dom';
import React from "react";
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
localStorage.getItem('isLoggedIn') === 'true'
? <Component {...props}/>
: <Redirect to='/login'/>
)} />
);
export default PrivateRoute;
This code for works fine, the problem is that I'm importing the <Redirect> from 'react-router/modules/Redirect' instead of using 'react-router-dom'.
To make this code work you just have to replace in main-page.js:
import Redirect from "react-router/modules/Redirect";
to
import { Redirect } from 'react-router-dom';
import { Navigate } from 'react-router-dom';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
localStorage.getItem('isLoggedIn') === 'true'
? <Component {...props}/>
: <Navigate to="/login" />
)} />
);
import React, { Component } from "react";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import { library } from "#fortawesome/fontawesome-svg-core";
import {
faHome,
faClock,
faTasks,
faStickyNote,
faCalendarWeek
} from "#fortawesome/free-solid-svg-icons";
import { connect } from "react-redux";
import store from "./store";
import { loadUser } from "./actions/authActions";
import Home from "./Home";
import SideNav from "./Components/SideNav";
import Recent from "./Components/Recent";
import TopBar from "./Components/TopBar";
import AddNote from "./AddNote";
import LogIn from "./Components/LogIn/LogIn.js";
import Register from "./Components/Register/Register";
import ToDo from "./Components/ToDo/ToDo";
import { timingSafeEqual } from "crypto";
library.add(faHome, faClock, faTasks, faStickyNote, faCalendarWeek);
class App extends Component {
componentDidMount() {
store.dispatch(loadUser());
}
componentDidUpdate(prevProps) {
if(this.props != this.prevProps) {
console.log("hello")
}
}
LogInContainer = () => {
return <Route path="/login" component={LogIn} />;
};
RegisterContainer = () => {
return <Route path="/register" component={Register} />;
};
DefaultContainer = () => {
return (
<div className="app_container">
<SideNav />
<TopBar />
<Route exact path="/" component={Home} />
<Route path="/recent" component={Recent} />
<Route path="/AddNote" component={AddNote} />
<Route path="/ToDo" component={ToDo} />
</div>
);
};
// Check for authenticaition
AuthRoute = ({ component: Component, props, ...rest }) => {
return (
<Route
{...rest}
render={props => {
if (this.props.auth.isAuthenticated) {
return <Component {...props} />;
}
else {
return (
<Redirect
to={{
pathname: "/login",
state: { from: this.props.location }
}}
/>
);
}
}}
/>
);
};
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/login" component={this.LogInContainer} />
<Route exact path="/register" component={this.RegisterContainer} />
<this.AuthRoute component={this.DefaultContainer} />
</Switch>
</BrowserRouter>
);
}
}
const mapStateToProps = (state) => ({
auth: state.auth
})
export default connect(mapStateToProps)(App);
How can app.js receive the new state from redux after logging in? The initial fetch it will get isAuthenticated = false. User then log ins but app.js isn't getting the new state. Am I implementing authenitcation wrong? comonentDidUpdate is throwing an error when trying to update props but feel like this is a bad way of doing it anyways
i working by react js router (react-router-dom v4.2) and Redux together and have strange varios problem
first i say i successfully used and run this but the problems
when i use the root route as first rote in route list router stop working!!
but when i use '/' route as last route everything is ok
<Switch>
<Route path="/blog" component={Blog} />
<Route path="/users/" component={Users} />
<Route path="/" component={Home} axact />
</Switch>
when i create routes as external component and import it to app routes not work
this is my route.js codes
import React, { Component } from 'react';
import { Switch, Route } from "react-router-dom";
// import Components
import Home from './components/Home'
import Blog from './components/blog/Blog'
import Users from './components/users/Users'
class router extends Component {
render() {
return (
<div>
<Switch>
<Route path="/" component={Home} axact />
<Route path="/blog" component={Blog} />
<Route path="/users/" component={Users} />
</Switch>
</div>
);
}
}
export default router;
this is my App.js codes:
import React, { Component } from 'react';
import { getUsers } from './store/actions'
import { connect } from 'react-redux'
import { withRouter } from "react-router-dom";
import Nav from './components/navigation/Nav';
import axios from 'axios';
const userApi = "https://jsonplaceholder.typicode.com/users"
class App extends Component {
componentWillMount() {
axios.get(userApi)
.then(response => {
let users = response.data
this.props.getUserList(users)
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div className="container">
<Nav />
<Router />
</div>
);
}
}
const mapDispatchToProps = dispatch => ({ getUserList: (api) => dispatch(getUsers(api)) })
export default withRouter(connect(null, mapDispatchToProps)(App));
when i use this codes everything is ok
import React, { Component } from 'react';
import { getUsers } from './store/actions'
import { connect } from 'react-redux'
import { Switch, Route, withRouter } from "react-router-dom";
import Home from './components/Home'
import Blog from './components/blog/Blog'
import Users from './components/users/Users'
import Nav from './components/navigation/Nav';
import axios from 'axios';
const userApi = "https://jsonplaceholder.typicode.com/users"
class App extends Component {
componentWillMount() {
axios.get(userApi)
.then(response => {
let users = response.data
this.props.getUserList(users)
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div className="container">
<Nav />
<Switch>
<Route path="/blog" component={Blog} />
<Route path="/users/" component={Users} />
<Route path="/" component={Home} axact />
</Switch>
</div>
);
}
}
const mapDispatchToProps = dispatch => ({ getUserList: (api) => dispatch(getUsers(api)) })
export default withRouter(connect(null, mapDispatchToProps)(App));