Why user becomes undefined when navigating to a different page - javascript

My user variable is defined after the component mounts after signing up or logging in but when navigating to another page it is null. I have this as the AuthContext component after the user signs in.
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user=>{
setCurrentUser(user);
})
{console.log(currentUser)}
return unsubscribe
})
const value = {
signup,
currentUser,
logout,
authError,
login
}
return(
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
)
This is my App.js Component.
function App() {
return (
<Router>
<div className = "App">
<AuthProvider>
<Routes>
<Route path="/" element={<Home/>}/>
<Route element= {<AuthRoute/>}>
{/*
If user is already signed in re-direct to home
*/}
<Route exact path = "/sign_up" element = {<SignUp/>} />
<Route exact path = "/login" element= {<SignIn/>}/>
</Route>
<Route exact path="/new_post" element ={<AuthRouteIfLoggedOut>
<SignUp/>
</AuthRouteIfLoggedOut>}/>
<Route exact path="/about" element={<About/>}/>
</Routes>
</AuthProvider>
</div>
</Router>
);
}
AuthContext is my context component.
Any reason why when I try to navigate to another page the user is undefined or is "signed-out" on that page only? But when I navigate back to my main page it is logged in and works properly. Any reason why when navigating to different pages currentUser is null?

You have to cache user and provider logic for your routes. Here is an example Authetication in React

Related

Restriction on pages after login in React

So I'm using react router v6 in my React App.
I have the following routes enabled in my app.js file
<Routes>
<Route path='/' component={<Home />} />
<Route path='/login' component={<SignUp />} />
<Route path='/signup' component={<Login />} />
</Routes>
Everything's fine and that. What I want to to do is to put restriction on pages. Now I know how to create PrivateRoutes and PublicRoutes based on LoggedIn User.
For this purpose I want the user to not be able to access Homepage after he or she signups.
Are there an functions for that or what strategy would I use.
I accomplished this using 'react-router-dom' and creating a PrivateRoute component. The following code is not tested but can give you some ideas. LoaderComponent is a loading animation of your choice can be toher component as well.
// Based on https://reactrouter.com/web/example/auth-workflow
// If the user is not yet authenticated.
const PrivateRoute: React.FC<PrivateRouteProps> = ({ children, path, ...props }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
//put your authentication logic
setIsAuthenticated(true);
}, []);
return (
<Route
path={path}
{...props}
render={() => (isAuthenticated ? children : <LoaderComponent />)}
/>
);
};
And in your router config
import { Switch } from 'react-router-dom';
<Switch>
<PrivateRoute exact path='/'>
<Home />
</PrivateRoute>
...
</Switch>

ReactJS Login page repeating on every url path

Here is my code, I am completely new to front end development can any one help me solve the issue, I want the user to be redirected to the login page if the user is not logged in but once he is logged in every thing should work fine but even when I click sign in, the login page shows up when I change the URL, The login page is appearing on every URL
Here's my code (i am new to front end pls dont judge)
import { useState } from 'react'
import { Route, Switch} from 'react-router-dom'
import Dashboard from "./pages/Dashboard";
import DatasetGenerator from "./pages/DatasetGenerator"
import Simulator from "./pages/Simulator"
function App() {
const [login, setlogin] = useState(true)
const [homepage, setHomepage] = useState(false)
const loginHandler = ()=>{
if(login == true){setlogin(false)
setHomepage(true)}
}
return (
<div>
{login && <SignIn loginHandler={loginHandler} />}
<Switch>
<Route path='/' exact>
{homepage && <Dashboard />}
</Route>
<Route>
{homepage && <DatasetGenerator path="/dataset-generator"/>}
</Route>
<Route path="/simulator">
{homepage && <Simulator />}
</Route>
</Switch>
</div>
)
}
export default App;
Seems like you want to conditionally render the login component OR the rest of your app. Since the login state and the homepage state appear to be mutually exclusive you probably don't need both (though perhaps we're missing some context).
return (
<div>
{login ? (
<SignIn loginHandler={loginHandler} />
) : (
<Switch>
<Route path='/' exact>
<Dashboard />
</Route>
<Route>
<DatasetGenerator path="/dataset-generator"/>
</Route>
<Route path="/simulator">
<Simulator />
</Route>
</Switch>
)}
</div>
)
A better solution would be to implement an auth workflow by creating authenticated route components that handle redirecting to a login route if not authenticated, otherwise allows the user to access the route.

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

How to redirect user to root route if the user refreshes the page on any other route in REACT ROUTER?

So, in my project I have two routes one is the root route and other is the /game route. And I always
want the user to start from the root route because the user needs to set a mandatory state variable before moving to /game route.
But if the user refreshes the page on game route I want to redirect to root route. So all I want is that the entry point to my application is always the root route.
<Router>
<Route path="/">
<Redirect to="/" />
</Route>
<Route exact path="/" render={() => <Home setLevel={setLevel} />}></Route>
<Route exact path="/game" render={() => <Game level={level} />}></Route>
</Router>
The setup above works on localhost but when I deploy my app on Netlify it doesn't work. So if the user refreshes the page on /game route, it says page not found.
Here's full code
import { useState } from "react";
import {
BrowserRouter as Router,
Link,
Redirect,
Route,
} from "react-router-dom";
const Home = ({ setLevel }) => {
return (
<>
<h1>Choose Difficulty</h1>
<ul>
<li onClick={() => setLevel("easy")}>Easy</li>
<li onClick={() => setLevel("hard")}>Hard</li>
</ul>
<Link to="/game">Play</Link>
</>
);
};
const Game = ({ level }) => {
return (
<>
<h1>Welcome to the game</h1>
<p>Your level is {level}</p>
</>
);
};
const App = () => {
const [level, setLevel] = useState(null);
return (
<Router>
<Route path="/">
<Redirect to="/" />
</Route>
<Route exact path="/" render={() => <Home setLevel={setLevel} />}></Route>
<Route exact path="/game" render={() => <Game level={level} />}></Route>
</Router>
);
};
export default App;
I haven't investigated your React set up too closely, but you may just be missing a _redirects file for your Netflify deployment: https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file
react-router-dom is a client side router, so when Netlify loads a page using server side rendering (aka, when you refresh or visit a page for the first time, that is not a client side redirect), it cannot find the route on the server. Adding a _redirects file will instruct Netlify how to serve up your pages on initial load.
Assuming that when the user refreshes the page, state level becomes null again.
Then update your code as below:
const Game = ({ level }) => {
// add a guard right here
if (!level) {
return <Redirect to="/"/>;
}
return (
<>
<h1>Welcome to the game</h1>
<p>Your level is {level}</p>
</>
);
};
const App = () => {
const [level, setLevel] = useState(null);
return (
<Router>
{ /* remove this code
* <Route path="/">
* <Redirect to="/" />
* </Route>
*/ }
<Route exact path="/" render={() => <Home setLevel={setLevel} />}></Route>
<Route exact path="/game" render={() => <Game level={level} />}></Route>
</Router>
);
};

How can I hide side navigation on some components?

As I am new on ReactJS. I tried many solutions to implement the show/hide side menu on different components.
Requirement is:
a. When user is logged in then side menu shows on all components.
b. When user is logged out then It shows only some of the components like Forgot Password or Terms and condition(menus name changed as per the authentication) but hides on Login Component.
App.js
<Router>
<SideNavigation />
<Routes />
</Router>
Routes.js
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/forgotPassword" component={ForgotPassword} />
<Route exact path="/termAndCondition" component={TermAndCondition} />
<PrivateRoutes exact path="/" component={Dashboard} />
<PrivateRoutes exact path="/emp" component={Employee} />
<PrivateRoutes exact path="/empList" component={EmployeeList} />
</Switch>
Use a simple state variable and keep track of the login status in your App.js. (for example - by useState() hook below👇)
const [isLoggedIn, setIsLoggedIn] = useState(false);
Pass a callback function to the Routes component and then to the Login Component.
<Routes onLogIn={()=>setIsLoggedIn(true)}/>
Routes.js Assuming it's a functional component (use this.props for class component).
<Route exact path="/login" >
<Login onLogIn={props.onLogIn}/>
</Route>
You can then call the onLogIn() function from the Login component and update the state.
Now, again in App.js -
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [canShowNav, setCanShowNav] = useState(false);
const [currentComponent, setCurrentComponent] = useState(''); //default component shown
useEffect(()=>{ //for determining canShowNav's value
if(isLoggedIn)setCanShowNav(true)
else{
if(currentComponent === 'login'){ //add any other components you want where nav should not be shown
setCanShowNav(false)
}
else setCanShowNav(true)
}
}, [isLoggedIn, currentComponent])
return(
<Router>
{canShowNav && <SideNavigation onComponentChange={(component)=>setCurrentComponent(component)}/>}
<Routes onComponentChange={(component)=>setCurrentComponent(component)} onLogIn={()=>setIsLoggedIn(true)}/>
</Router>
)
Then call onComponentChange("componentName") from the SideNavigation whenever a link is clicked, passing the component's name which is clicked.
You can pass the onComponentChange function to the login page too, to change the state when user clicks on Forgot Password or anything like that and update the state.
Routes.js
<Route exact path="/login" >
<Login onLogIn={props.onLogIn} onComponentChange={props.onComponentChange}/>
</Route>
Let me know if it helps you or not!✌

Categories