Navigate in different Routes React - javascript

I have an authentication system, and I want to show different <Routes> with different available paths considering from login state.
I uesd <Navigate/> element for redirection from hidden pages depending login state. But there is a problem. <Navigate/> redirects without considering the state.
For example, when I logged in and try to open Login page I must redirects to a Main page, and when I don't logged in and try to open profile I must redirect to Login Page. And when I try to open any of this pages I automaticly redirects to Main page.
routes.jsx:
import React from 'react';
import {
Routes,
Route,
Navigate
} from 'react-router-dom';
import Profile from './pages/Profile/Main/Profile';
import Login from './pages/Auth/Login/Login';
import Register from './pages/Auth/Register/Register';
import Main from './pages/Main/Main';
import { Loans } from './pages/Profile/Active/Loans';
import ErrorPage from './pages/errorPage/ErrorPage';
export const useRoutes = isAuthenticated => {
if(isAuthenticated){
return (
<Routes>
<Route path='/profile' exact>
<Route index path=":id" element={<Profile/>}/>
<Route path="loans" element={<Loans/>} exact/>
</Route>
<Route path='/' exact element={<Main/>}/>
<Route
path="*"
element={<ErrorPage/>}
/>
<Route
path="/auth/*"
element={<Navigate to="/" replace />}
/>
</Routes>
);
} else {
return (
<Routes>
<Route path='/auth' exact>
<Route path='login' element={<Login/>} exact />
<Route path="register" exact element={<Register/>}/>
<Route
path=""
element = {
<Navigate to="login" replace />
}
/>
</Route>
<Route path='/' exact element={<Main/>}/>
<Route
path="/profile/*"
element={<Navigate to="/auth/login" replace />}
/>
<Route
path="*"
element={<ErrorPage/>}
/>
</Routes>
)
}
}
App.jsx:
import {
BrowserRouter
} from 'react-router-dom';
import {useRoutes} from './routes';
import 'materialize-css';
import { useAuth } from './hooks/auth.hook';
import { AuthContext } from './context/auth.context';
function App() {
const {token, userId, login, logout} = useAuth();
const isAuthenticated = !!token;
const routes = useRoutes(isAuthenticated);
return (
<AuthContext.Provider value = {{
token, login, logout, userId, isAuthenticated
}}>
<BrowserRouter>
<div className="container">
{routes}
</div>
</BrowserRouter>
</AuthContext.Provider>
);
}
export default App;

One issue that may be causing this is you check authentication based on whether the token exists. Debug the output of that variable to see if it is cleared correctly when you log out. Next, you are determining authentication once inside of App(), fetching the routes from useRoutes(), and then rendering the app without ever checking again if the authentication is still valid. A better approach would be something like this:
const auth = useAuth();
return ({auth.isAuthenticated ? (
<Fragment>
<Link to="/account">Account ({auth.user.email})</Link>
<Button onClick={() => auth.signout()}>Signout</Button>
</Fragment>
) : (
<Link to="/signin">Signin</Link>
)});

Related

How to handle private routes in react app

I am encountering a problem with my private routing setup. Currently, I use the user variable in the App.js to determine if a user is logged in or not, in order to restrict access to private routes. The issue with this method is that if a user attempts to directly access a private page (such as "mysolutions"), they will be immediately redirected to the homepage due to the delay in fetching the user data from the database during the initial website load.
I would like to know how can I fix this issue.
My App.js code:
import React, { Suspense } from "react"
import { Navigate, Route, Routes } from "react-router-dom"
import rocketLoader from "./assets/animated_illustrations/rocketLoader.json"
import Layout from "./components/layouts/Layout"
import Meta from "./components/meta/Meta"
import LottieAnimation from "./components/reusable/LottieAnimation"
import ScrollToTop from "./components/reusable/ScrollToTop"
import { useAuthContext } from "./hooks/useAuthContext"
import "./App.css"
// lazy loading components
const Homepage = React.lazy(() => import("./pages/Homepage"))
const Dashboard = React.lazy(() => import("./pages/Dashboard"))
const MySolutions = React.lazy(() => import("./pages/MySolutions"))
const App = () => {
const { authIsReady, user } = useAuthContext()
return (
<>
<Meta routes={routes} />
<div>
<Suspense
fallback={
<div className="flex justify-center items-center min-h-screen">
<LottieAnimation animationDataFile={rocketLoader} />
</div>
}
>
<ScrollToTop>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Homepage />} />
<Route path="challenges" element={<Dashboard />} />
<Route
path="mysolutions"
element={user ? <MySolutions /> : <Navigate to="/" />}
/>
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>
</ScrollToTop>
</Suspense>
</div>
</>
)
}
export default App
You can use authIsReady variable from useAuthContext() for check the current user data inside the private route.
And with this variable you can simply add if condition to private route like :
<ScrollToTop>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Homepage />} />
<Route path="challenges" element={<Dashboard />} />
{authIsReady && (
<Route
path="mysolutions"
element={user ? <MySolutions /> : <Navigate to="/" />}
/>
)}
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>
</ScrollToTop>
I would create a loading page, which is shown to the user until the fetch is completed and we are able to decide if we can let advance to the private route or not. Would this solution work for you?

How to write/create a private route in react-router-dom v6?

I tried creating a private route using react-router-dom v6 as shown below in React JS
import React from 'react';
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom';
import * as ROUTES from './constants/routes';
import { Home, Signin, Signup, Browse } from './pages';
import { IsUserRedirect, ProtectedUserRedirect } from './helpers/routes';
function App() {
const user=null;
return (
<>
<Router>
<Routes>
<Route exact path={ROUTES.HOME} element={<IsUserRedirect user={user} path={ROUTES.BROWSE} />}>
<Route element={<Home />} />
</Route>
<Route exact path={ROUTES.BROWSE} element={<ProtectedUserRedirect user={user} path={ROUTES.SIGN_IN} />}>
<Route element={<Browse />} />
</Route>
<Route exact path={ROUTES.SIGN_IN} element={<IsUserRedirect user={user} path={ROUTES.BROWSE} />}>
<Route element={<Signin />} />
</Route>
<Route exact path={ROUTES.SIGN_UP} element={<IsUserRedirect user={user} path={ROUTES.BROWSE} />}>
<Route element={<Signup />} />
</Route>
</Routes>
</Router>
</>
);
}
export default App;
and the helper components are implemented as shown below
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
export const IsUserRedirect = ({path, user, children}) => {
console.log(Boolean(user))
return (
user?<Navigate to={path} replace />:<Outlet />
)
}
export const ProtectedUserRedirect = ({path, user, children}) => {
console.log(Boolean(user))
return (
user?<Outlet />:<Navigate to={path} replace />
)
}
NO ERROR AT TERMINAL AND CONSOLE but I'm not getting any output. The components seems to not rendering properly. Could you please me how to write better private route in v6 of router-dom. Reference: https://dev.to/iamandrewluca/private-route-in-react-router-v6-lg5
THANKS IN ADVANCE

Getting 404 | Page Not found Nextjs

I created my page routing with react-router v5 and everything works well. If I click on the link, it takes me to the page, but when I reload the page I get a "404 | Page Not Found" error on the page.
import React, { useEffect, useState } from 'react'
import Home from './dexpages/Home'
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
import Dashboard from './dexpages/dashboard';
import Swapping from './dexpages/swapping'
import Send from './dexpages/send';
import Airdrops from './dexpages/airdrops'
function Main() {
const [mounted, setMounted] = useState(false)
useEffect(() => {
if (typeof window !== "undefined") {
setMounted(true)
}
}, [])
return (
<>
{mounted &&
<BrowserRouter>
<div className="min-h-screen" style={{ overflowX: 'hidden' }}>
<Routes>
<Route path="/airdrops" element={<Airdrops />} />
<Route path="/send" element={<Send />} />
<Route path="/swap" element={<Swapping />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/" element={<Home />} />
</Routes>
</div>
</BrowserRouter>
}
</>
)
}
export default Main;
This is my Main Component where I create all the routing.
This is the error I'm getting when I reload the page
Don't use React Router with next.js.
Next.js has its own routing mechanism which is used for both client-side routing and server-side routing.
By using React Router, you're bypassing that with your own client-side routing so when you request the page directly (and depend on server-side routing) you get a 404 Not Found.
Next.js has a migration guide.
Your paths need to be adjusted. For the home page it is fine to be routed to / however for the other pages there is no need for a backslash, remove the backslash from the Airdrops, Send, Swapping, and Dashboard paths respectively and you should be fine.
Try this below for each of the routes.
<Route path="airdrops" element={<Airdrops />} />
<Route path="send" element={<Send />} />
<Route path="swap" element={<Swapping />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="/" element={<Home />} />

Errors in react-router-dom

I am learning connecting MongoDB Realm to react by following this article. The problem with this article is that it is outdated, and the newer version of react doesn't support component = {Home} in react-router and perhaps not the render = {()={}} also.
When I shamelessly copy-pasted all code and then ran it I got this warning
index.js:21 Matched leaf route at location "/" does not have an element. This means it will render an with a null value by default resulting in an "empty" page.
then I changed the code(a line) for the Home page just for testing to this
<Route path="/" element={()=><MongoContext.Consumer>{(mongoContext) => <Home mongoContext={mongoContext}/>}</MongoContext.Consumer>} />
Then I got a new warning, LOL!
Warning
Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
I have no what to do now. So, if anyone knows how to solve this, then it will be helpful for me.
App.js
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from "./pages/Home"
import * as Realm from 'realm-web'
import Authentication from './pages/Authentication';
import LogOut from './pages/Logout';
import Navigation from './components/Navigation';
import MongoContext from './MongoContext';
import 'bootstrap/dist/css/bootstrap.min.css'
import { Container } from "react-bootstrap"
import { useEffect, useState } from 'react';
function renderComponent (Component, additionalProps = {}) {
return <MongoContext.Consumer>{(mongoContext) => <Component mongoContext={mongoContext} {...additionalProps} />}</MongoContext.Consumer>
}
function App() {
const [client, setClient] = useState(null)
const [user, setUser] = useState(null)
const [app, setApp] = useState(new Realm.App({ id: "restaurant_app-qbafd" }))
useEffect(() => {
async function init() {
if (!user) {
setUser(app.currentUser ? app.currentUser : await app.logIn(Realm.Credentials.anonymous()))
}
if (!client) {
setClient(app.currentUser.mongoClient('mongodb-atlas'))
}
}
init();
}, [app, client, user])
return (
<BrowserRouter>
<Navigation user={user} />
<MongoContext.Provider value={{ app, client, user, setClient, setUser, setApp }}>
<div className="App">
<header className="App-header">
<Routes>
<Route path="/signup" render={() => renderComponent(Authentication, {type: 'create'})} />
<Route path="/signin" render={() => renderComponent(Authentication)} />
<Route path="/logout" render={() => renderComponent(LogOut)} />
<Route path="/" element={()=><MongoContext.Consumer>{(mongoContext) => <Home mongoContext={mongoContext}/>}</MongoContext.Consumer>} />
</Routes>
</header>
</div>
</MongoContext.Provider>
</BrowserRouter>
);
}
export default App;
Try to wrap all your routes in the MongoContext.Consumer:
<BrowserRouter>
<Navigation user={user} />
<MongoContext.Provider
value={{ app, client, user, setClient, setUser, setApp }}
>
<MongoContext.Consumer>
{(mongoContext) => (
<div className='App'>
<header className='App-header'>
<Routes>
<Route
path='/signup'
element={
<Authentication mongoContext={mongoContext} type='create' />
}
/>
<Route
path='/signin'
element={<Authentication mongoContext={mongoContext} />}
/>
<Route
path='/logout'
element={<LogOut mongoContext={mongoContext} />}
/>
<Route path='/' element={<Home mongoContext={mongoContext} />} />
</Routes>
</header>
</div>
)}
</MongoContext.Consumer>
</MongoContext.Provider>
</BrowserRouter>;

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.

Categories