React Router Maintain state during page refresh - javascript

Was setting up react router to only display my Navbar on all routes except the login page. I created a Layout component that handles this and will return user to Login page if they are not authenticated. I currently store my state to local storage and if the value is true, the user is still authenticated and can remain on their current page. This works great although when the page is refreshed, it returns the user back to the login page even though local storage item is set to true. Any advice on what I may be doing wrong or another workaround for what I'm trying to accomplish? Thank you.
App.js
export const AuthContext = createContext();
function App() {
const stillAuth = window.localStorage.getItem("auth state");
console.log("still auth: " + stillAuth);
const [isAuthenticated, setIsAuthenticated] = useState(stillAuth);
console.log("isAuth: " + isAuthenticated);
return (
<div className="App d-flex flex-column" style={{ minHeight: "100vh" }}>
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
<Routes>
<Route path="login" element={<Login />} />
<Route path="/" element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/DevExamples" element={<DeveloperExamples />} />
<Route path="/CliExamples" element={<ClientExamples />} />
<Route path="*" element={<Error />} />
</Route>
</Routes>
</AuthContext.Provider>
<Footer />
</div>
);
}
function Layout() {
const { isAuthenticated } = useContext(AuthContext);
if (isAuthenticated != true) return <Navigate to="/login" />;
return (
<>
<NavBar />
</>
);
}
export default App;
Login.jsx
const Login = () => {
const [username, setUserName] = useState("");
const [password, setPassword] = useState("");
const navigate = useNavigate();
const { isAuthenticated, setIsAuthenticated } = useContext(AuthContext);
const handleLogin = () => setIsAuthenticated(true);
const handleLogout = () => setIsAuthenticated(false);
const updateToken = (username, password) => {
// make axios call and check if username & password are valid
window.localStorage.setItem("auth state", true);
handleLogin();
navigate("/");
// excluded for now to test and develop
// LoginService.authLogin({
// username: username,
// password: password,
// }).then(() => {
// });
};
return (
<div>
<h1>Please Log In</h1>
{/* <form onSubmit={handleSubmit}> */}
<label>
<p>Username</p>
<input
type="text"
onChange={(e) => setUserName(e.target.value)}
value={username}
required
/>
</label>
<br />
<label>
<p>Password</p>
<input
type="password"
onChange={(e) => setPassword(e.target.value)}
value={password}
required
/>
</label>
<div>
<button
// component={Link}
// to="/home"
onClick={() => updateToken(username, password)}
>
<Link to="/">Sign In</Link>
</button>
</div>
{/* </form> */}
</div>
);
};
Sandbox

Issue
The issue here is that values stored into localStorage are stringified.
window.localStorage.setItem("state", true);
const state = window.localStorage.getItem("state"); // "true"
Once the boolean "auth state" value is saved into localStorage it becomes a string literal, the Layout is comparing a string literal against a boolean.
console.log("true" != true); // true
console.log("true" !== true); // true
console.log("false" != true); // true
console.log("false" !== true); // true
The expression isAuthenticated != true will always evaluate true and the redirect to "/login" will be effected.
Solution
You should generally be in the habit of explicitly JSON stringifying and parsing the data you persist to localStorage.
window.localStorage.setItem("state", JSON.stringify(true));
const state = JSON.parse(window.localStorage.getItem("state")); // true
function App() {
const stillAuth = JSON.parse(window.localStorage.getItem("auth state")); // <-- parse
const [isAuthenticated, setIsAuthenticated] = useState(stillAuth);
console.log({ stillAuth, isAuthenticated });
return (
<div className="App d-flex flex-column" style={{ minHeight: "100vh" }}>
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
<Routes>
<Route path="login" element={<Login />} />
<Route path="/" element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/DevExamples" element={<DeveloperExamples />} />
<Route path="/CliExamples" element={<ClientExamples />} />
<Route path="*" element={<Error />} />
</Route>
</Routes>
</AuthContext.Provider>
<Footer />
</div>
);
}
import { Outlet } from 'react-router-dom';
function Layout() {
const { isAuthenticated } = useContext(AuthContext);
if (!isAuthenticated) return <Navigate to="/login" replace />;
return (
<>
<NavBar />
<Outlet /> // <-- so nested routes can render content!!
</>
);
}
Login
const updateToken = (username, password) => {
// make axios call and check if username & password are valid
window.localStorage.setItem("auth state", JSON.stringify(true)); // <-- stringify
handleLogin();
navigate("/");
// excluded for now to test and develop
// LoginService.authLogin({
// username: username,
// password: password,
// }).then(() => {
// });
};

Related

how to stop redirect to signUp page once in dashboard- reactjs

I'm trying to restrict the user to prevent back to signup page once moved to dashboard.
created one signup page and dashboard page.
once the user signUp done it should navigate to dashboard and if the user clicks on back button we should block the user to returning back to signup page.
App.js:
export const countContext = createContext();
const initialState = {
basket: [],
};
const reducer = (state, action) => {
switch (action.type) {
case 'ADD_TO_BASKET':
return {
...state,
basket: [...state.basket, action.item],
};
default:
return state;
}
};
function App() {
const [basketCount, dispatch] = useReducer(reducer, initialState);
return (
<>
<Router>
<AuthProvider>
<countContext.Provider
value={{ countState: basketCount, countDispatch: dispatch }}
>
<Routes>
<Route
exact
path='/'
element={
basketCount.length !== 1 ? (
<Navigate to='/SignUp' replace='true' />
) : (
<Navigate to='/Dashboard' replace='true' />
)
}
/>
<Route
exact
path='/Dashboard'
element={
basketCount.length !== 1 ? (
<Navigate to='/SignUp' replace='true' />
) : (
<Navigate to='/Dashboard' replace='true' />
)
}
/>
<Route exact path='/' element={<SignUp />} />
<Route exact path='/Dashboard' element={<Dashboard />} />
<Route exact path='/SignUp' element={<SignUp />} />
</Routes>
</countContext.Provider>
</AuthProvider>
</Router>
</>
);
}
But, even after signUp it is not navigating to the dashboard remaining same in signUp page.
function SignUp() {
const nameRef = useRef();
const countCountext = useContext(countContext);
const mobileRef = useRef();
const otpRef = useRef();
const auth = getAuth();
const { signNumber } = useAuth();
const [error, setError] = useState();
const [loading, setLoading] = useState(false);
const [visible, setVisible] = useState(true);
const navigate = useNavigate();
async function handleSubmit(e) {
e.preventDefault();
try {
setError('');
setLoading(true);
const code = otpRef.current.value;
window.confirmationResult
.confirm(code)
.then((result) => {
countCountext.countDispatch({
type: 'ADD_TO_BASKET',
item: {
name: nameRef.current.value,
mobile: mobileRef.current.value,
},
});
navigate('/Dashboard', { replace: true });
})
.catch((error) => {
console.log(error.message);
});
} catch {
setError('Failed to Sign Up');
}
setLoading(false);
}
function getOtp() {
window.recaptchaVerifier = new RecaptchaVerifier(
'sign-in-button',
{
size: 'invisible',
callback: (response) => {
onSignInSubmit();
},
},
auth
);
}
async function onSignInSubmit(e) {
e.preventDefault();
getOtp();
const phoneNumber = '+91' + mobileRef.current.value;
const appVerifier = window.recaptchaVerifier;
await signNumber(auth, phoneNumber, appVerifier);
setLoading(false);
}
const notNull = (e) => {
if (e.target.value.length === 10) {
console.log(e.target.value.length);
setVisible(false);
} else {
setVisible(true);
setLoading(true);
}
};
return (
<div className='outer' autoComplete='off'>
<Card className='center' autoComplete='off'>
<Card.Body>
<h2>Sign Up</h2>
<Form onSubmit={handleSubmit} method='POST' autoComplete='off'>
<div id='sign-in-button'></div>
{error && <Alert variant='danger'>{error}</Alert>}
<Form.Group id='name'>
<Form.Label>Enter Your Name:</Form.Label>
<Form.Control
required
ref={nameRef}
autoComplete='off'
></Form.Control>
</Form.Group>
<Form.Group id='mobile-number'>
<Form.Label>Enter Your Mobile Number:</Form.Label>
<Form.Control
autoComplete='off'
type='number'
name='mobile'
required
ref={mobileRef}
onChange={(e) => notNull(e)}
></Form.Control>
<br />
</Form.Group>
<Button onClick={onSignInSubmit} disabled={visible}>
Get OTP
</Button>
<br />
<Form.Group>
<Form.Label disabled={visible}>Enter Your OTP:</Form.Label>
<br />
<Form.Control
autoComplete='off'
disabled={visible}
type='number'
name='opt'
required
ref={otpRef}
></Form.Control>
<br />
</Form.Group>
<Button disabled={loading} type='submit'>
SIGN IN
</Button>
</Form>
</Card.Body>
</Card>
<div className='w-100 text-center mt-2'>
<Link to='/Login'>Doctor Login</Link>
</div>
</div>
);
}
Even after signUp the URL not changing to Dashboard and the page remains same at signUp
This is the output i'm getting.
I think the issue is that you are trying to render multiple routes for the same path. In other words, you've some duplicate route paths. It looks like the "/Dashboard" route redirects to itself which will certainly cause a render loop.
It looks like you are trying to create some form of route protection based on the basketCount array length.
Create a layout route component that takes the basketCount as a prop and handles the redirect to the appropriate routes or renders an Outlet component for the wrapped routes.
Example:
import { Outlet } from 'react-router-dom';
const BasketCheckLayout = ({ basketCount }) => {
return basketCount === 1
? <Outlet />
: <Navigate to='/SignUp' replace />;
};
App
Wrap the dashboard route with a layout route rendering the BasketCheckLayout component. The "/" home path should just redirect user to the dashboard route (and let the BasketCheckLayout component handle redirecting to "/SignUp").
Rename the basketCount state to be more accurate for what it represents. Here I'll just rename it state. Pass state.basket.length as basketCount to the BasketCheckLayout component which simply checks the scaler value.
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<Router>
<AuthProvider>
<countContext.Provider
value={{ countState: state, countDispatch: dispatch }}
>
<Routes>
<Route
path='/'
element={<Navigate to='/Dashboard' replace />}
/>
<Route
element={<BasketCheckLayout basketCount={state.basket.length} />}
>
<Route path='/Dashboard' element={<Dashboard />} />
</Route>
<Route path='/SignUp' element={<SignUp />} />
</Routes>
</countContext.Provider>
</AuthProvider>
</Router>
</>
);
}
Note the all the replace props are truthy/falsey boolean props.

React / firebase app flashes login screen before auth finishes

When you signup/ login/ refresh the page the login page flashes just before going to the correct page. I tried putting a loader in but all it does is do a loader animation before it flashes then goes to correct page. Any idea how to get this to not happen?
function App(){
const [user, setUser] = useState();
const [loading, setLoad] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(getAuth(), setUser, setLoad(false))
return () => {unsubscribe()}
}, [])
const AuthenticatedRoute = ({children}) => {
let isAuthenticated;
if(user !=null){
isAuthenticated = true;
}else{
isAuthenticated = false;
}
if(!loading){
return isAuthenticated? children: <Navigate to="/signin"/>
}else{
return <Loading/>
}
}
const UnauthenticatedRoute = ({children}) => {
let isAuthenticated;
if(user !=null){
isAuthenticated = true;
}else{
isAuthenticated = false;
}
if(!loading){
return !isAuthenticated? children: <Navigate to="/home"/>
}else{
return <Loading/>
}
}
return(
<Router>
<div className="App">
{
<Routes>
<Route exact path="/" element={<UnauthenticatedRoute><PreHome/></UnauthenticatedRoute>}/>
<Route path='/home' element={<AuthenticatedRoute><Home/></AuthenticatedRoute>} />
<Route exact path="/signin" element={<UnauthenticatedRoute><Signin/></UnauthenticatedRoute>} />
<Route exact path="/signup" element={<UnauthenticatedRoute><Signup/></UnauthenticatedRoute>} />
</Routes>
}
</div>
</Router>
)
}
Sign Out code:
This one line has been working for signing out
<button onClick={() => signOut(getAuth())}>Sign Out</button>
Sign In code:
async function OnFormSubmit(e){
e.preventDefault();
const auth = getAuth();
try{
isLoading(true);
await signInWithEmailAndPassword(auth, email, pw)
isLoading(false);
}catch(err){
console.log(err)
}
}
Issues
The loading state is only cleared when there's an error in onAuthStateChanged.
The route protector components are declared inside another React component. This is anti-pattern. When new "instances" of these components are declared each time the parent App component rerenders, it will unmount/mount the component's subReactTree.
The components don't wait for the user's authentication status to resolve before deciding to redirect or render the routed content.
Solution
Move the route protector components out on their own. Render an Outlet for nested routes to be rendered into. This allows you to render these as layout routes instead of individual wrapper components.
Use a proper "loading" state. Use undefined user state as the "loading state".
Example:
import { Outlet, Navigate } from 'react-router-dom';
const AuthenticatedRoute = ({ user }) => {
if (user === undefined) return <Loading />;
return user
? <Outlet />
: <Navigate to="/signin" />;
};
const UnauthenticatedRoute = ({ user }) => {
if (user === undefined) return <Loading />;
return user
? <Navigate to="/home" />
: <Outlet />;
};
...
function App(){
const [user, setUser] = useState();
useEffect(() => {
const unsubscribe = onAuthStateChanged(getAuth(), setUser);
return unsubscribe;
}, []);
return(
<AuthContextProvider>
<Router>
<div className="App">
<Routes>
<Route element={<UnauthenticatedRoute user={user} />}>
<Route path="/" element={<PreHome />} />
<Route path="/signin" element={<Signin />} />
<Route path="/signup" element={<Signup />} />
</Route>
<Route element={<AuthenticatedRoute user={user} />}>
<Route path='/home' element={<Home />} />
</Route>
</Routes>
</div>
</Router>
</AuthContextProvider>
);
}

Redirect to dashboard after successful payment

This is my app.js where all the routes
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route element={<PrivateRoute />}>
<Route exact path="/dashboard" element={<Dashboard />} />
<Route exact path="/payment" element={<Payment />} />]
</Route>
<Route exact path="/login" element={<Login />} />
</Routes>
</Router>
This is my PrivateRoute component
function PrivateRoute({ fetchMe, ...props }) {
const [type, setType] = useState("xxxxx");
const isAuthenticated = localStorage.getItem("authToken");
const navigate = useNavigate();
const [lodar, setLodar] = useState(false);
useEffect(() => {
setLodar(false);
if (isAuthenticated) {
(async () => {
const {
value: { user },
} = await fetchMe();
console.log({ data: user.step1 });
if (user.step === 1) {
navigate("/payment");
}
setLodar(false);
})();
}
}, []);
return (
<Spin indicator={antIcon} spinning={lodar}>
{isAuthenticated ? (
<>
<Header type={type} setType={setType} />
<Outlet context={[type, setType]} />
</>
) : (
<Navigate to="/login" />
)}
</Spin>
);
}
export default PrivateRoute;
So what I want to do here is to always redirect the user to the "/payment" after signup. and if the user again comes after login then it will again redirect it to the payment page so for that I am keeping a flag in my database user.step and checking by api call on the PrivateRoute component.
The issue is it loads the "/dashboard" page before the fetchUser api call which should not happen and show some lodar before. How can I do that?
Is there any better approach doing this since I always have to make an api call?
Kindly help!!!
Assuming <Spin indicator={antIcon} spinning={lodar}> is conditionally rendering either a loading spinner/indicator or the wrapped children then I think the issue is just the initial lodar state value. It doesn't appear the lodar state is ever toggled true.
I suggest starting with an initially true state so the component doesn't immediately render the Outlet or redirect when the component mounts, prior to any auth checks happening via the useEffect hook.
Example:
function PrivateRoute({ fetchMe, ...props }) {
const [type, setType] = useState("xxxxx");
const isAuthenticated = localStorage.getItem("authToken");
const navigate = useNavigate();
const [lodar, setLodar] = useState(true); // <-- initially true
useEffect(() => {
setLodar(true); // <-- toggle true when starting async logic
if (isAuthenticated) {
(async () => {
const {
value: { user },
} = await fetchMe();
console.log({ data: user.step1 });
if (user.step === 1) {
navigate("/payment");
}
setLodar(false); // <-- clear loading when complete
})();
}
}, []);
return (
<Spin indicator={antIcon} spinning={lodar}>
{isAuthenticated ? (
<>
<Header type={type} setType={setType} />
<Outlet context={[type, setType]} />
</>
) : (
<Navigate to="/login" />
)}
</Spin>
);
}

User Auth Context returns empty object in react with Firebase

I am trying to use Context API for user authentication to Firebase from my React app. I wrote the code for the context provider in AuthContext.js which includes all the auth functions. It successfully runs and also provides all the currentuser info.
AuthContext.js
const userAuthContext = createContext();
export function UserAuthContextProvider({ children }) {
const [user, setUser] = useState({});
function logIn(email, password) {
return signInWithEmailAndPassword(auth, email, password);
}
function signUp(email, password) {
return createUserWithEmailAndPassword(auth, email, password);
}
function logOut() {
return signOut(auth);
}
function googleSignIn() {
const googleAuthProvider = new GoogleAuthProvider();
return signInWithPopup(auth, googleAuthProvider);
}
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (currentuser) => {
console.log("Auth", currentuser);
setUser(currentuser);
});
return () => {
unsubscribe();
};
}, []);
return (
<userAuthContext.Provider
value={{ user, logIn, signUp, logOut, googleSignIn }}
>
{children}
</userAuthContext.Provider>
);
}
export function useUserAuth() {
return useContext(userAuthContext);
}
I have also wrapped the App component in UserAuthContextProvider. But when I try to use it in other components like Homepage, it returns an empty object for user. I did a lot of research finding the solution but couldn't really find where the problem lies.
App.js
const App = () => {
return (
<UserAuthContextProvider>
<div className="app">
<div className="navbar">
<Navbar />
</div>
<div className="main">
<Layout>
<div className="header">
<Title level={2} style={{ margin: "0px" }}>
Welcome
</Title>
<Text style={{ margin: "0px", color: "grey" }}>
Here's what's happening in the crypto world
</Text>
</div>
<div
className="
routes"
>
<Routes>
<Route exact path="/" element={<Homepage />} />
<Route exact path="/exchanges" element={<Exchanges />} />
<Route
exact
path="/cryptocurrencies"
element={<Cryptocurrencies />}
/>
<Route
exact
path="/crypto/:coinId"
element={<CryptoDetails />}
/>
<Route exact path="/news" element={<News />} />
<Route exact path="/watchlist" element={<Watchlist />} />
</Routes>
</div>
</Layout>
<div className="footer">
<Typography.Title
level={5}
style={{ color: "white", textAlign: "center" }}
>
Cryptocon <br />© All rights reserved
</Typography.Title>
<Space split={<Divider type="vertical" />}>
<Link to="/">Home</Link>
<Link to="/exchanges">Exchanges</Link>
<Link to="/news">News</Link>
</Space>
</div>
</div>
</div>
</UserAuthContextProvider>
);
};
export default App;
Homepage.jsx
const { user } = useUserAuth();
const { data, isFetching } = useGetCryptosQuery(10);
const globalStats = data?.data?.stats;
if (isFetching) return <Loader />;
-> console.log("The user is: " + user);
return (
<>
...
</>
);
};

I want to render the starting page based on user logged in or not on react

What I want is to show the Homepage only if user has previously logged in and didn't logged out. But is user logged out previously then show loginpage. I'm saving auth status to local storage like this: key:auth, value:true/false. Depending on auth value I want to render the starting page.
This is my App.js:
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import Signup from "./Components/Signup";
import Login from "./Components/Login";
import { Routes, Route, Navigate } from "react-router-dom";
import HomePage from "./Components/HomePage";
import { useEffect, useState } from "react";
function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const authStatus=localStorage.getItem('auth')
const setAuth = (value) => {
setIsAuthenticated(value);
//alert(value);
};
useEffect(()=>{
setIsAuthenticated(authStatus)
},[])
return (
<>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
</Routes>
</>
);
}
export default App;
Its always opening Homepage in the starting but I want Homepage if user login status is true which is saved on localStorage of the browser and Login page if login status is false.
This is my login.js:
import React, { useState } from "react";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import { Link, useNavigate } from "react-router-dom";
const initialValues = {
email: "",
password: "",
};
export default function Login({setAuth}) {
const navigate = useNavigate();
const [values, setValues] = useState(initialValues);
function validateForm() {
return values.email.length > 0 && values.password.length > 0;
}
const handleSubmit = (e) => {
e.preventDefault();
Login();
};
const handleInputChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
setValues({
...values,
[name]: value,
});
};
function Login() {
let retrievedData = localStorage.getItem("registeredUsers");
let users = JSON.parse(retrievedData);
let Found = users.find(function (user, index) {
if (user.email === values.email && user.password === values.password) {
return true;
}
});
if (Found) {
setAuth(true)
let auth = true;
localStorage.setItem("auth", JSON.stringify(auth));
//navigate("/");
} else {
alert("Error email/password");
}
}
return (
<div className="LoginContainer">
<div style={{ display: "flex", width: "100%" }}>
<Form onSubmit={handleSubmit}>
<Form.Group size="lg" controlId="email">
<Form.Label>Email</Form.Label>
<Form.Control
autoFocus
type="email"
name="email"
value={values.email}
onChange={handleInputChange}
/>
</Form.Group>
<Form.Group size="lg" controlId="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
name="password"
value={values.password}
onChange={handleInputChange}
/>
</Form.Group>
<Button
style={{ marginTop: 10, width: 400 }}
block
size="lg"
type="submit"
// disabled={!validateForm()}
>
Login
</Button>
</Form>
</div>
<text style={{ marginTop: 10 }}>
Don't have an account? <Link to="/signup">Register</Link>
</text>
</div>
)
}
Issues
Your initial isAuthenticated state matches your unauthenticated state.
The render doesn't handle any conditional rendering of the homepage or redirecting to your login page.
The Login component isn't passed the setAuth callback.
Solution
Initialize the isAuthenticated from localStorage, use the useEffect hook with dependency on isAuthenticated to persist authentication state changes to localStorage.
function App() {
const [isAuthenticated, setIsAuthenticated] = useState(
() => JSON.parse(localStorage.getItem('auth')) || false
);
const setAuth = (value) => {
setIsAuthenticated(value);
//alert(value);
};
useEffect(()=>{
localStorage.setItem("auth", JSON.stringify(isAuthenticated));
}, [isAuthenticated]);
return (
<>
<Routes>
<Route
path="/"
element={isAuthenticated
? <HomePage />
: <Navigate to="/login" replace />
}
/>
<Route path="/login" element={<Login setAuth={setAuth} />} />
<Route path="/signup" element={<Signup />} />
</Routes>
</>
);
}
Login
Update the login function to only call the setAuth callback and then imperatively navigate to the homepage.
const handleSubmit = (e) => {
e.preventDefault();
login();
};
...
function login() {
const users = JSON.parse(localStorage.getItem("registeredUsers")) || [];
const found = users.some(user => user.email === values.email && user.password === values.password);
if (found) {
setAuth(found);
navigate("/", { replace: true });
} else {
alert("Error email/password");
}
}
It looks like your getting your auth info from local storage but not actually using it anywhere. You should be able to do a conditional route based on if the user is authenticated or not. Something like this.
<Routes>
<Route path="/" element={ isAuthenticated ? <HomePage /> : <Login />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
</Routes>
Or you could also use a redirect when you are running your setAuth method. If the current path is / and they dont have the auth coookie then redirect them to /login
This answer explains a few different ways to achieve the redirect if you chose that way.
For those looking for another way of solving this with React Router 6:
First import the following from react-router-dom
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
Then on your return function:
<BrowserRouter>
<Routes>
<Route index path="/" element={<Home />}></Route>
<Route path="/register" element={isAuthenticated ? <Navigate replace to="/" /> : <Register />}></Route>
<Route path="/login" element={isAuthenticated ? <Navigate replace to="/" /> : <Login />}></Route>
</Routes>
</BrowserRouter>

Categories