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!✌
Related
The code below is responsible for building the sidebar on the site. In this case, the sidebar is 2 filter options, made in the form of a drop-down list.
This side bar is located on all pages of the site. However, the problem is that when switching between pages, the selected filter options are not saved. That is, if on the first page, the user checks something in the filters, then when going to the second page, the values ​​in the filters will not be saved. And I would like the selected parameters for filtering to be saved when moving from page to page.
export default function App() {
return (
<ThemeProvider theme={theme} style="width: 100vw; height: 100vh">
<Header/>
<BrowserRouter>
<Routes>
<Route exact path='/test' element={<Test filterKey='device'/>}/>
<Route exact path='/devices' element={<DeviceList/>}/>
<Route exact path='/devices/:deviceId' element={<DeviceId/>}/>
<Route exact path='/devices/:deviceId/:userId' element={<UserId/>}/>
<Route exact path='/devices/:deviceId/:userId/:sessionId' element={<SessionId/>}/>
<Route exact path='/devices/:deviceId/:userId/:sessionId/:pocketId' element={<PocketId/>}/>
<Route path="*" element={<Navigate to="/devices" replace />}/>
</Routes>
<Footer/>
</BrowserRouter>
</ThemeProvider>
);
}
Since you are saying Sidebar component should be in each page with same functionality, I would place it in App component then it will be always in pages without changing it's filters
export default function App() {
return (
<ThemeProvider theme={theme} style="width: 100vw, height: 100vh">
<BrowserRouter>
<Header/>
<div style={{width: '100%', display: 'flex'}}>
<Routes>
<Route exact path='/test' element={<Test filterKey='device'/>}/>
<Route exact path='/devices' element={<DeviceList/>}/>
<Route exact path='/devices/:deviceId' element={<DeviceId/>}/>
<Route exact path='/devices/:deviceId/:userId' element={<UserId/>}/>
<Route exact path='/devices/:deviceId/:userId/:sessionId' element={<SessionId/>}/>
<Route exact path='/devices/:deviceId/:userId/:sessionId/:pocketId' element={<PocketId/>}/>
<Route path="*" element={<Navigate to="/devices" replace />}/>
</Routes>
<Sidebar />
</div>
<Footer/>
</BrowserRouter>
</ThemeProvider>
);
}
to share the State between React Components you can initiate your state in the main App and then pass it to all components via props.
for example, your "Component A" :
// pass the state & setState in the component as props :
export const ComponentA = ({
isFilterMethodExpanded,
setIsFilterMethodExpanded,
isFilterDateTimeExpanded,
setIsFilterDateTimeExpanded
}) => {
// whatever you want to do with the state
return <div>...</div>;
};
and your "Component B" :
// pass the state & setState in the component as props :
export const ComponentB = ({
isFilterMethodExpanded,
setIsFilterMethodExpanded,
isFilterDateTimeExpanded,
setIsFilterDateTimeExpanded
}) => {
// whatever you want to do with the state
return <div>...</div>;
};
then your main App will look like :
// Initiate the state in the main App :
export default function App() {
const [isFilterMethodExpanded, setIsFilterMethodExpanded] = useState(false);
const [isFilterDateTimeExpanded, setIsFilterDateTimeExpanded] = useState(
false
);
// pass the state & setState in the component props in the return part :
return (
<div className="App">
<ComponentA
isFilterMethodExpanded={isFilterMethodExpanded}
setIsFilterMethodExpanded={setIsFilterMethodExpanded}
isFilterDateTimeExpanded={isFilterDateTimeExpanded}
setIsFilterDateTimeExpanded={setIsFilterDateTimeExpanded}
/>
<ComponentB
isFilterMethodExpanded={isFilterMethodExpanded}
setIsFilterMethodExpanded={setIsFilterMethodExpanded}
isFilterDateTimeExpanded={isFilterDateTimeExpanded}
setIsFilterDateTimeExpanded={setIsFilterDateTimeExpanded}
/>
</div>
);
}
This will keep the State when navigating between React Components, but not on the browser refresh, If you want to Persist the State on page reload then you can check this article
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
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>
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.
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