Login route is not getting renderd on logout react - javascript

I am new to the react js . Now , Here, what I have is a private Route.
const PrivateRoute = ({ component: Component, isFetching, hasUserLogIn, path, ...rest }) => {
hasUserLogIn = localStorage.getItem("access_token");
if (hasUserLogIn !== undefined && hasUserLogIn !== null) {
hasUserLogIn = true;
} else {
hasUserLogIn = false;
}
console.log("hasUserLogIn",hasUserLogIn);
return hasUserLogIn ?
(
<Route
{...rest}
path={path}
component={Component}
/>
)
:
(
<Redirect
to={{
pathname: "/login",
state: { from: path }
}}
/>
)
};
<div>
<Router history={history}>
<div>
{this.props.isFetching && <Loading />}
<Switch>
<PrivateRoute exact path="/:job?" component={LandingScreen} />
<PrivateRoute exact path="/quiz-setup/:job" component={QuizSetupMain} />
<PrivateRoute exact path="/quiz-questions" component={FetchedQuestionComponent} />
<Route exact path="/login" component={LoginComponent} />
<Route exact path="/*" component={NotFound} something="foo" />
</Switch>
</div>
</Router>
</div>
)
handleLogout = () => {
this.props.logoutUser();
}
Here, first one is as soon as I log In success.
So, In login success I have written like ,
history.push('/'); then it redirects to the LandingScreen Component.
Now, I do have one dropdown, on change of that I am adding :job param in the route which is like ,
onchange ,
history.push({
pathname: "/" + `${jdId}`
});
So It again rerenders the LandingScreen component.
Now, on click of the logout button,
I want to redirect the use to the login page that is /login.
So, on click of logout what I do is ,
localStorage.clear();
history.push('/');
so with this it is not rendering the LoginComponent and also route does not get changes ,
But If I remove the :job? from the route it redirects to the login I mean renders the login component.
Can any one help me with this ?

Related

React-Router-Dom changing states of the page

Hi guys i have a problem. When I enter "dashboard" which is a private route it redirects me to "login" first then to dashboard. True and False are playing together. How can i fix it to not redirect me to login then to dashboard.
video example:
https://cdn.aboutluc.xyz/images/rc64kb6af92sswn3r4mv.mp4
code:
import React, {
useState,
useEffect
} from "react"
import { toast } from "react-toastify"
import {
BrowserRouter as Router,
Routes,
Route,
Navigate
} from "react-router-dom"
import {
Login,
Register,
Dashboard,
} from "./Pages"
import {
Navbar
} from "./Components"
import './App.css'
import "react-toastify/dist/ReactToastify.css"
import 'bootstrap/dist/css/bootstrap.min.css'
toast.configure()
const App = () => {
const [ isAuthenticated, setIsAuthenticated ] = useState()
const setAuth = (boolean) => {
setIsAuthenticated(boolean)
}
const isAuth = async () => {
try {
const res = await fetch("http://localhost:5000/api/auth/verify", {
headers: { JwtToken: localStorage.JwtToken }
});
const parseRes = await res.json();
parseRes === true ? setIsAuthenticated(true) : setIsAuthenticated(false);
} catch (error) {
console.error(error)
}
}
useEffect(() => {
isAuth()
}, [])
return (
<>
<Router>
<Navbar setAuth={setAuth} isAuthenticated={isAuthenticated} />
<Routes>
<Route
exact
path="/login"
element={
isAuthenticated ? (
<Navigate replace={true} to="/dashboard" />
) : (
<Login setAuth={setAuth} />
)
}
/>
<Route
exact
path="/register"
element={
isAuthenticated ? (
<Navigate replace={true} to="/dashboard" />
) : (
<Register setAuth={setAuth} />
)
}
/>
<Route
exact
path="/dashboard"
element={
isAuthenticated ? (
<Dashboard setAuth={setAuth} />
) : (
<Navigate replace={true} to="/login" />
)
}
/>
</Routes>
</Router>
</>
)
}
export default App
The possible issue I see is the "gap" on the initial render where the isAuthenticated state is undefined and the useEffect hook callback to set that state hasn't run yet. If you attempt to directly access a protected route then regardless of actual auth status the code will bounce you to the login route.
For this you typically want to use the "third" indeterminant state to "hold" on either redirecting to auth or allowing access through to the protected component until the auth status is confirmed.
Abstract the auth status into auth layout components.
const AuthLayout = ({ isAuthenticated }) => {
if (isAuthenticated === undefined) return null; // or loading spinner, etc...
return isAuthenticated
? <Outlet />
: <Navigate to="/login" replace />;
};
const AnonymousLayout = ({ isAuthenticated, to }) => {
if (isAuthenticated === undefined) return null; // or loading spinner, etc...
return isAuthenticated
? <Navigate to={to} replace />
: <Outlet />;
};
User the layouts to guard/protect specific routes.
<Routes>
<Route
element={(
<AnonymousLayout isAuthenticated={isAuthenticated} to="/dashboard" />
)}
>
<Route path="/login" element={<Login setAuth={setAuth} />} />
<Route path="/register" element={<Register setAuth={setAuth} />} />
</Route>
<Route element={<AuthLayout isAuthenticated={isAuthenticated} />}>
<Route path="/dashboard" element={<Dashboard setAuth={setAuth} />} />
</Route>
</Routes>
Note: You only ever call isAuth when the App component mounts. You may want to call this function or otherwise validate your auth token a little more often than this. Passing isAuth into the route wrappers and invoking also in an useEffect hook probably isn't a terrible idea.

Routes not working as desired in React JS

I am trying to build a full stack application with User login/logout functionality.
I want to protect certain pages such that they can only be viewed when the user is logged in. For login I have created a REST API and I am using session storage to keep track of whether the user is logged in or not.
validateUser = () => {
let user = {
username: this.state.email,
password: this.state.password,
//status: "LOGGED_IN"
};
UserService.authenticateUser(user).then((res) => {
if(res.data === 'SUCCESS') {
window.sessionStorage.setItem("isUserLogged", true);
} else if(res.data === 'FAILURE') {
window.sessionStorage.setItem("isUserLogged", false);
this.resetLoginForm();
this.setState({"error":"Invalid username or password"});
}
})
};
Tis is my App.js
function App() {
return (
<div>
<Router>
<HeaderComponent/>
<div className="container">
<Switch>
<Route path="/" exact component={LandingPageComponent}></Route>
{/* <Route path ="/customers" component = {ListCustomerComponent}></Route> */}
{/* <Route path ="/add-customer/:id" component = {CreateCustomerComponent}></Route> */}
<Route path = "/view-customer/:id" component = {ViewCustomerComponent}></Route>
<Route path = "/admin-login" component = {AdminLoginComponent}></Route>
<Route path = "/admin-register" component = {AdminResgisterComponent}></Route>
<Route path="/customers" exact render={() => (
window.sessionStorage.getItem("isUserLogged") === "true"
? <ListCustomerComponent />
: <Redirect to='/admin-login' />
)} />
<Route path="/add-customer/:id" exact render={() => (
window.sessionStorage.getItem("isUserLogged") === "true"
? <CreateCustomerComponent />
: <Redirect to='/admin-login' />
)} />
</Switch>
</div>
<FooterComponent/>
</Router>
</div>
);
}
export default App;
Everything works fine if I don't check my session storage. But when I try to implement the conditional routes as shown above I start getting errors.
If I just put simple routes, then I don't encounter this error.
Any help would be highly appreciated.
You didn't pass Route props into your component. So history does not included in props, you can console.log(this.props) to check what this.props contains.
To fix it, let's pass Route props into your components
<Route path="/add-customer/:id" exact render={(props) => (
window.sessionStorage.getItem("isUserLogged") === "true"
? <CreateCustomerComponent {...props} /> // ADD PROPS HERE
: <Redirect to='/admin-login' />
} />
You didn't show what you did on ListCustomerComponent.
You could try to encapsulate your component using HOC withRouter or if you are using Functional component, use useHistory hook.
// on export class component
export default withRouter(YourComponent)
in functional component, you can use
const YourComponent = ()=>{
const history = useHistory();
// then you can say something such as
// history.push(...)
return <>...your view here...</>
}
export default YourComponent;
<Switch>
{/* Login Sections goes Here */}
<Route exact path='/' component={MainPage} />
<Route exact path='/login' component={Login} />
<Route exact path='/admin/' component={LoginAdmin} />
<Route exact path='/register' component={Register} />
{/* AdminUser ROutes goes here */}
<SuperUserDashboard>
<Route exact path='/admin/dashboard' component={Dashboardpage} />
<Route exact path='/admin/users' component={UsersAdmin} />
</SuperUserDashboard>
<Route exact path='' component={Notfound} />
</Switch>
in superuser dashboard check if user is authenticated if not redirect to admin login page else all the routes will be visible

Private Route React router always redirects to first Route

Actually I had no problem with directing to another route by clicking a button, but somehow I can't direct manually by changing the URL. Every time I was about changing the URL (ex: localhost:3000/proposal), it always directs me to the first Route. Here's the Route in order :
<Switch>
<Route exact path="/" component={Landing} /> // => always goin here
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
{/* Dashboard */}
<PrivateRoute
exact
path="/home"
component={Home}
StickyNav={StickyNavbar}
/>
<PrivateRoute
exact
path="/proposal"
component={Proposal}
StickyNav={StickyNavbar}
/>
<PrivateRoute
exact
path="/laporan"
component={Laporan}
StickyNav={StickyNavbar}
/>
<Route component={NotFound} />
</Switch>
It doesn't direct me to Landing if I change the URL to non-private route. Here's my private route code :
import React from "react"
import { Route, Redirect } from "react-router-dom"
import { connect } from "react-redux"
import PropTypes from "prop-types"
const mapStateToProps = state => ({
auth: state.auth
})
const PrivateRoute = ({ component: Component, auth, ...rest }) => (
<Route
{...rest}
render={props =>
auth.isAuthenticated === true ? (
<Component {...props} {...rest} />
) : (
<Redirect to="/login" />
)
}
/>
)
PrivateRoute.propTypes = {
auth: PropTypes.object.isRequired
}
export default connect(mapStateToProps)(PrivateRoute)
Based on #zhuber said, the auth object from react-redux doesn't call before the private route was called. So I changed the condition from isAuthenticated using localStorage like this :
!isEmpty(localStorage.jwtToken) ? (
<Component {...props} {...rest} />
) : (
<Redirect to="/login" />
)

implement auth route - with nested /signin and /signup routes

I want to implement simple signin/signup routs with react-router-dom.
here is the App.js
<div className="App">
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/auth" component={SignInSignUpPage} />
</Switch>
</div>
and I'm using route guard like so :
const HomePage = ({ currentUser }) => {
return currentUser ? <HomePageComponent /> : <Redirect to="/auth" />;
};
Now what I want to do, is to have the /auth route, for users to login, and inside a container of both the signInSignUp, I have a Link that will change the route to auth/signup to view the signup page like so:
const SignInSignUpPage = ({ match }) => {
return (
<SignInSignUpContainer>
<Route path={`${match.path}`} component={SignIn} />
<Route path={`${match.path}/signup`} component={SignUp} />
</SignInSignUpContainer>
);
};
which in turn will render the correct component :
const SignInSignUpContainer = ({ match, children, history }) => {
const { isExact } = match;
return (
<SignInSignUpContainerContent>
<SignInSignUpContainerContentForm>
<LockIconContainer iconName="icon-lock-closed" />
{children}
</SignInSignUpContainerContentForm>
</SignInSignUpContainerContent>
);
};
I must be doing it wrong, and the react-router-dom docs are addressing the protected route, which I didn't find suitable for this case.
Just from looking at the structure: you don't send match prop down to SignInSignUpContainer, and it seems that SignInSignUpContainer expects it.
should be :
const SignInSignUpPage = ({ match }) => {
return (
<SignInSignUpContainer match={match}>
<Route path={`${match.path}`} component={SignIn} />
<Route path={`${match.path}/signup`} component={SignUp} />
</SignInSignUpContainer>
);
};
same with history prop

Objects are not valid as a React child using react router v4

This is my wrapper component aka auth component to allow only authed user to access.
Auth.js
render() {
const { Component: component, ...rest } = this.props;
return (
<Route>
{rest}
render={props =>
this.isAuth === true ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login"
}}
/>
)
}
</Route>
);
}
What's wrong with it? Here's my route declaration
Index.js
render(
<BrowserRouter>
<div className="App">
<Switch>
<Route path="/login" component={Login} />
<Auth path="/dashboard" component={Dashboard} />
</Switch>
</div>
</BrowserRouter>,
document.getElementById("root")
);
I've made a demo to reproduce the problem here
https://codesandbox.io/s/5xm202p1j4
I used the same concept in the official doc, https://reacttraining.com/react-router/web/example/auth-workflow just that instead of making the auth.js a pure function I make it a class base container so that I can call api or check the token of the user exist or not in my localstorage, what's the problem exactly?
Did you mean to do something like this:
render() {
const { Component: component, ...rest } = this.props;
return (
<Route
{...rest}
render={props =>
this.isAuth === true ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login"
}}
/>
)
}
/>
);
}
By having rest and render in the <Route> tag so the rest are passed to the <Route>?

Categories