react router dom v6.2.1 - javascript

hello everyone I have an issue with react-router-dom v6.2.1
const MainRoutes = () => {
return (
<Routes>
<Route path={"/"} element={<Login/>}/>
<Route path={"/dashboard*"} render={<PrivateRoutes/>}/>
</Routes>
);
};
const PrivateRoutes = () => {
return (
<Routes>
<Route path="/dashboard/" element={<Dashboard/>}/>
<Route path="/dashboard/:id" element={<Book/>}/>
</Routes>
);
};
/dashboard and /dashboard/:id render blank for me

export const MainRoutes = () => {
return (
<Routes>
<Route path={"/"} element={<Login />} />
<Route path={"/dashboard/*"} element={<PrivateRoutes />} />
</Routes>
);
};
const PrivateRoutes = () => {
return (
<div>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/:id" element={<Book />} />
</Routes>
</div>
);
};
you should use like this
https://reactrouter.com/docs/en/v6/getting-started/overview

hi hasan
you need to change
<Route path={"/dashboard*"} render={<PrivateRoutes/>}/>
to
<Route path={"/dashboard/*"} element={<PrivateRoutes/>}/>
have a look on this post

Related

How to protect routes in React 18?

I have an admin dashboard and want that only admins are able to see the pages. So I set a condition into my router. When I am logged in, I am able to open every page, but I get the warning:
No routes matched location “/pagename”
Navbar and Sidebar staying in the same position, so that every page opens in a div named ContentWrapper.
How can I get rid of this warning?
Code:
const admin = useAppSelector((state)=>state.auth.user?.isAdmin);
return (
<Container>
<Router>
<Routes>
<Route path="/" element={<Login/>}/>
</Routes>
{admin &&
<>
<Navbar/>
<Wrapper>
<Sidebar/>
<ContentWrapper>
<Routes>
<Route path="/home" element={<Home/>}/>
<Route path="/sales" element={<Sales/>}/>
<Route path="/analytics" element={<Analytics/>}/>
<Route path="/transactions" element={<Transactions/>}/>
<Route path="/reports" element={<Reports/>}/>
<Route path="/mail" element={<Mail/>}/>
<Route path="/feedback" element={<Feedback/>}/>
<Route path="/messages" element={<Messages/>}/>
<Route path="/manage" element={<Manage/>}/>
<Route path="/user" element={<User/>}/>
<Route path="/products" element={<Products/>}/>
<Route path="/productlistChild" element={<ProductlistChild/>}/>
<Route path="/productlistWomen" element={<ProductlistWomen/>}/>
<Route path="/productlistMen" element={<ProductlisttMen/>}/>
<Route path="/productlistSportschuhe" element={<ProductlistSportschuhe/>}/>
<Route path="/productlistSneaker" element={<ProductlistSneaker/>}/>
<Route path="/cardImages" element={<CardImages/>}/>
<Route path="/sneakerImage" element={<SneakerImage/>}/>
<Route path="/sliderImage" element={<SliderImages/>}/>
<Route path="/newsletterBackground" element={<NewsletterBackground/>}/>
<Route path="/descriptionItems" element={<DescriptionItems/>}/>
</Routes>
</ContentWrapper>
</Wrapper>
</>
}
</Router>
</Container>
);
}
Did something similar recently
You can create a PrivateRoute Component
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRouteAdmin = ({ isLoggedIn, role }) => {
return isLoggedIn && role === 'Admin' ? <Outlet /> : <Navigate to="/login" />;
};
export default PrivateRouteAdmin;
and then you can use it in your App.js like this
<Route element={<PrivateRouteAdmin isLoggedIn={isLoggedIn} role={user?.data?.role} />}>
<Route element={<DashboardWrapper />}>
{PublicRoutesAdmin.map((route, index) => {
return <Route key={index} path={route.path} element={<route.component />} />;
})}
</Route>
</Route>
PublicRoutesAdmin.map has just all the routes in a separate file, nothing fancy.
You can have other public routes pout of the private route component
I would resolve this by creating two groups of routes: Private and Public:
const PublicRoutes = () => (
<Fragment>
<Route path="/public/a"><ComponentA /></Route>
<Route path="/public/b"><ComponentB /></Route>
</Fragment>
)
const PrivateRoutes = () => (
<Fragment>
<Route path="/private/a"><PrivComponentA /></Route>
<Route path="/private/b"><PrivComponentB /></Route>
</Fragment>
)
And then have a RootRouter component which conditionally renders either the public or the private routes based on a condition:
const RootRouter = () => {
return (
<Router>
<Routes>
{admin ?
<Fragment>
<PublicRoutes />
<PrivateRoutes />
</Fragment> :
<PublicRoutes />
}
</Routes>
</Router>
)
}
This way, you are rendering the PublicRoutes AND the PrivateRoutes for the admin, but only the PublicRoutes for non-admin users.

how to fix TypeError: state.user.currentUser is null node js

in requestmethods.js
import axios from "axios";
const BASE_URL = "http://localhost:5000/api/";
const TOKEN = JSON.parse(JSON.parse(localStorage.getItem("persist:root"))?.user)
?.currentUser?.accessToken;
export const publicRequest = axios.create({
baseURL: BASE_URL,
});
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${TOKEN}` },
});
and in app.js
function App() {
const admin = useSelector((state) => state.user.currentUser.isAdmin);
return (
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
{admin && (
<>
<Topbar />
<div className="container">
<Sidebar />
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<UserList />
</Route>
<Route path="/user/:userId">
<User />
</Route>
<Route path="/newUser">
<NewUser />
</Route>
<Route path="/products">
<ProductList />
</Route>
<Route path="/product/:productId">
<Product />
</Route>
<Route path="/newproduct">
<NewProduct />
</Route>
</div>
</>
)}
</Switch>
</Router>
);
}
I am trying to make if the user is admin show the admin pages, if not show the login page , but when I run npm start I get blank screen , when inspect the page I get these types of error
1=> Uncaught TypeError: state.user.currentUser is null
const admin = useSelector((state) => state.user.currentUser.isAdmin);
Uncaught TypeError: state.user.currentUser is null
This states that the currentUser property in your state.user object is null hence it cannot read the isAdmin property.
One way to avoid this use the safe(elvis) operator '?'.
So use state?.user?.currentUser?.isAdmin instead of state.user.currentUser.isAdmin
Assuming you are using react-router v6, your app.js could look like this
function App() {
const admin = useSelector((state) => state?.user?.currentUser?.isAdmin);
const RequireAuth = () => {
if (!admin) {
return Navigate('/login');
}
return <Outlet/>;
};
return (
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
<Topbar />
<div className="container">
<Sidebar />
<Route element={<RequireAuth />}>
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<UserList />
</Route>
<Route path="/user/:userId">
<User />
</Route>
<Route path="/newUser">
<NewUser />
</Route>
<Route path="/products">
<ProductList />
</Route>
<Route path="/product/:productId">
<Product />
</Route>
<Route path="/newproduct">
<NewProduct />
</Route>
</Route>
</div>
</Switch>
</Router>
);
}
You have a good article here

setLoginUser is not a function

I am making a login application when i am clicking the login button the i am reciving an error (loginPage.js:33 Uncaught (in promise) TypeError: setLoginUser is not a function)
here is the code of app.js
function App() {
const [user,setLoginUser] = useState({})
return(
<div className='App'>
<BrowserRouter>
< Routes>
<Route path="/homepage" element={user && user?._id? <Homepage /> : <Login setLoginUser={setLoginUser} />}/>
<Route path="/login" element={<Login />} setLoginUser={setLoginUser}/>
<Route path="/register" element={<Register />} />
</Routes>
</BrowserRouter>
</div>
)
}
and here is the code of loginPage.js where error is occuring
const Login = ({ setLoginUser }) => {
const login = () => {
axios.post("http://localhost:4000/login", user)
.then(res => {
alert(res.data.message)
console.log(res.data.user)
setLoginUser(res.data.user)
navigate('/homepage')
})
}
}
You have to pass your setLoginUser function to Login component in your routes.
<Route path="/login" element={<Login setLoginUser={setLoginUser} />} />
You should replace :
<Route path="/login" element={<Login />} setLoginUser={setLoginUser}/>
by
<Route path="/login" element={<Login setLoginUser={setLoginUser}/>} />
I don't think it's a good idea to path variable like that in the root element but this should works.
Why do you have <BrowserRouter> and <Routes> ?

React component rerendering indefinitely when using Context with separate routes in Router

I have separate routes for some pages in my app, and I'm using Context to pass some props between 2 components. How the router part looks:
const NonLandingPages = () => {
return (
<div className='w-full flex flex-wrap min-h-screen bg-dark bg-main-bg 3xl:bg-main-bg-xl text-white z-10'>
<TrackedSitesProvider
value={{
trackedSites,
setTrackedSites,
updateTrackedSites
}}
>
<Switch>
<Route path='/login' component={LoginPage} />
<Route path='/signup' component={SignupPage} />
<Route path='/overview' component={OverviewPage} />
<Route path='/add_new_site' component={AddNewSite} />
<Route path='/registration_successful' component={RegistrationSuccessful} />
<Route path='/confirm_registration/:token' component={ConfirmRegistration} />
<Route path='/password_reset_successful' component={PasswordResetSuccessful} />
<Route path='/delete_successful' component={DeleteSuccessful} />
<Route exact path='/reset_password' component={ResetPassword} />
<Route path='/reset_password/:token' component={ConfirmResetPassword} />
<Route path='/delete_account' component={DeleteAccount} />
<Route path='/send_review' component={SendReview} />
<Route path='*' component={PageNotFound} />
</Switch>
</TrackedSitesProvider>
</div>
);
};
return (
<div className='app-basic-appearance'>
<Router>
<Switch>
<Route exact path='/' >
<LandingPage/>
</Route>
<Route component={NonLandingPages} />
</Switch>
</Router>
</div>
);
Context code:
import { createContext, useContext } from 'react';
import { TrackedSites } from '../types/';
interface ContextProps {
trackedSites: TrackedSites,
setTrackedSites: Function,
updateTrackedSites: Function
}
export const TrackedSitesContext = createContext<ContextProps | undefined>(undefined);
export const TrackedSitesProvider = TrackedSitesContext.Provider;
export const useTrackedSites = (): ContextProps => {
const context = useContext(TrackedSitesContext);
if (context === undefined) {
throw new Error('useTrackedSites must be used within a TrackedSitesProvider');
}
return context;
};
Function which uses context:
const trackedSitesContext = useTrackedSites();
useEffect(() => {
(async () => {
const token = await auth.checkTokenAndRefreshIfPossible();
if (!token) {
history.push('/login');
return;
}
const data = await getExistingSites();
if (data) {
trackedSitesContext.setTrackedSites(data);
}
setWaitingForServerResponse(false);
})();
}, []);
For whatever reason, component which contains useEffect hook pictured above is constantly getting re-rendered. Problem disappears if I put all of my routes in 1 place, like this:
<TrackedSitesProvider
value={{
trackedSites,
setTrackedSites,
updateTrackedSites
}}
>
<Router>
<Switch>
<Route exact path='/' component={LandingPage} />
<Route path='/login' component={LoginPage} />
<Route path='/signup' component={SignupPage} />
<Route path='/overview' component={OverviewPage} />
<Route path='/add_new_site' component={AddNewSite} />
<Route path='/registration_successful' component={RegistrationSuccessful} />
<Route path='/confirm_registration/:token' component={ConfirmRegistration} />
<Route path='/password_reset_successful' component={PasswordResetSuccessful} />
<Route path='/delete_successful' component={DeleteSuccessful} />
<Route exact path='/reset_password' component={ResetPassword} />
<Route path='/reset_password/:token' component={ConfirmResetPassword} />
<Route path='/delete_account' component={DeleteAccount} />
<Route path='/send_review' component={SendReview} />
<Route path='*' component={PageNotFound} />
</Switch>
</Router>
</TrackedSitesProvider>
Any kind of help is appreciated.

Can't pass a function to a component via <Route />

setErm is a function and is undefined in Erm component. Although the App component receives it. If I pass anything like something='foo' the ERM component get's it but not setErm={props.setErm}
const App = props => {
console.log("props in App", props);
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/erm"
render={props => <Erm {...props} setErm={props.setErm} />}
/>
<Route exact path="/:weekId" component={Week} />
<Route exact path="/:weekId/:dayId" component={Day} />
</Switch>
</div>
</Router>
);
};
The problem in your code is that in your Erm component props here refer to the Route component props not App props so you can change your code to use the props of App to something like this:
const App = props => {
console.log('props in App', props);
const appProps = props; // add this line to refer to App props
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/erm"
render={props => <Erm {...props} setErm={appProps.setErm} />}
/>
<Route exact path="/:weekId" component={Week} />
<Route exact path="/:weekId/:dayId" component={Day} />
</Switch>
</div>
</Router>
);
};
Or you can use destructuring:
const App = ({ setErm }) => {
console.log('props in App', props);
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/erm"
render={props => <Erm {...props} setErm={setErm} />}
/>
<Route exact path="/:weekId" component={Week} />
<Route exact path="/:weekId/:dayId" component={Day} />
</Switch>
</div>
</Router>
);
};
As you can see you now able to use the top props of App component

Categories

Resources