How can I arrange my Routes on the App component - javascript

I have various routes and I also have some data from context api that I want to pass to certain routes, excluding some. So,
There is the <UserContext.Provider> that should be wrapped inside all the routes.
There is also the <Route element={<PrivateRoute />}> that sould be wrapped inside most of the routes because it should be checking the authenticated user.
And then there are components like <FruitsData> and <WeatherData> that I should only use to wrap <Route path="training" element={<Training />} /> which is inside <Route element={<PrivateRoute />}> and <UserContext.Provider>
So, my question. How can I wrap the component mentioned in no.3 the right way without having to wrap it around all the other components like I have done below?
<UserContext.Provider value={user}>
<WeatherData>
<FruitsData>
<Routes>
<Route element={<PrivateRoute />}>
<Route path="/" element={<Dashboard />} />
<Route path="/test" element={<TestPage />} />
<Route path="training" element={<Training />} />
<Route path="fruit-details/:fruitId" element={<FruitDetails />} />
<Route path="my-farm" element={<MyFarmList />} />
<Route path="add-farm" element={<AddFarm />} />
<Route path="farm-details" element={<FarmDetails />} />
<Route path="add-post" element={<AddPost />} />
<Route path="post-details/:postId" element={<PostDetails />} />
<Route path="infestation-details/:infestationId" element={<InfestationDetails />} />
<Route path="farm-details/:username/:farmId" element={<FarmDetails />} />
<Route path="farm-details/:username/:farmId/fruits" element={<FarmFruits />} />
<Route path="area" element={<Area />} />
<Route path="shop" element={<Shop />} />
<Route path="packages" element={<Packages />} />
<Route path="seedlings" element={<Seedlings />} />
<Route path="profile" element={<Profile />} />
<Route path="product-details/:seedlingId" element={<ProductDetails />} />
<Route path="pricing" element={<Pricing />} />
<Route path="community" element={<Community />} />
<Route path="complete-profile" element={<CompleteProfile />} />
</Route>
<Route path="admin/" element={<AdminPrivateRoute />}>
<Route path="home" element={<Home />} />
<Route path="farmers" element={<Farmers />} />
<Route path="farms" element={<Farms />} />
</Route>
</Routes>
</FruitsData>
</WeatherData>
</UserContext.Provider>
Thank you

I don't see any overt issue with the way all the context providers wrap the entirety of the routes, but if you are trying to limit the scope of any specific provider then the solution here is to have them render an Outlet component instead of the children prop and render them as layout routes.
Example:
const UserLayout = () => {
... logic/state/etc ...
return (
<UserContext.Provider value={user}>
<Outlet />
</UserContext.Provider>
);
};
const FruitesWeatherLayout = () => {
... logic/state/etc ...
return (
<WeatherData>
<FruitsData>
<Outlet />
</FruitsData>
</WeatherData>
);
};
...
<Routes>
<Route element={<UserLayout />}> // <-- layout route
<Route element={<PrivateRoute />}>
<Route path="/" element={<Dashboard />} />
<Route path="/test" element={<TestPage />} />
<Route element={<FruitesWeatherLayout />}> // <-- layout route
<Route path="training" element={<Training />} />
</Route>
<Route path="fruit-details/:fruitId" element={<FruitDetails />} />
<Route path="my-farm" element={<MyFarmList />} />
<Route path="add-farm" element={<AddFarm />} />
<Route path="farm-details" element={<FarmDetails />} />
<Route path="add-post" element={<AddPost />} />
<Route path="post-details/:postId" element={<PostDetails />} />
<Route path="infestation-details/:infestationId" element={<InfestationDetails />} />
<Route path="farm-details/:username/:farmId" element={<FarmDetails />} />
<Route path="farm-details/:username/:farmId/fruits" element={<FarmFruits />} />
<Route path="area" element={<Area />} />
<Route path="shop" element={<Shop />} />
<Route path="packages" element={<Packages />} />
<Route path="seedlings" element={<Seedlings />} />
<Route path="profile" element={<Profile />} />
<Route path="product-details/:seedlingId" element={<ProductDetails />} />
<Route path="pricing" element={<Pricing />} />
<Route path="community" element={<Community />} />
<Route path="complete-profile" element={<CompleteProfile />} />
</Route>
<Route path="admin/" element={<AdminPrivateRoute />}>
<Route path="home" element={<Home />} />
<Route path="farmers" element={<Farmers />} />
<Route path="farms" element={<Farms />} />
</Route>
</Route>
</Routes>

Related

Context Provider is not a Route component error

I'm getting this error when I wrap some of my routes in a Context Provider tag. I basically need to send the logged user context to each of these routes for them to use or modify. The value sent in the provider is this:
const [loggedUser, setLoggedUser] = useState(null)
const value = useMemo(() => {{ loggedUser, setLoggedUser }}, [loggedUser, setLoggedUser])
And here is the code:
return (
<>
<Routes>
<Route path="/" element={ <MainPage /> } />
<UserContext.Provider value={value}>
<Route path="/login" element={<LoginMenu/>} />
<Route path="/register" element={<RegisterMenu/>} />
<Route path="/dashboard" element={<Dashboard tasks={tasks} />} />
</UserContext.Provider>
</Routes>
</>
)
Only Route component can be a child of a Route component. Abstract the UserContext.Provider component into a layout route.
Example:
import { Routes, Route, Outlet } from 'react-router-dom';
const UserContextProvider = () => (
<UserContext.Provider value={value}>
<Outlet />
</UserContext.Provider>
);
...
<Routes>
<Route path="/" element={<MainPage />} />
<Route element={<UserContextProvider />}>
<Route path="/login" element={<LoginMenu />} />
<Route path="/register" element={<RegisterMenu />} />
<Route path="/dashboard" element={<Dashboard tasks={tasks} />} />
</Route>
</Routes>
Or wrap the entire Routes in the UserContext.Provider component.
Example:
return (
<UserContext.Provider value={value}>
<Routes>
<Route path="/" element={ <MainPage /> } />
<Route path="/login" element={<LoginMenu />} />
<Route path="/register" element={<RegisterMenu />} />
<Route path="/dashboard" element={<Dashboard tasks={tasks} />} />
</Routes>
</UserContext.Provider>
);

react nested routes default path blank page

How can I make the parent path render a default outlet in react router v6 nested routes?
As you can see in the example I want to make "/dashboard" path take me to "/dashboard/home" by default.
For now it's just rendering a blank screen in the Outlet.
<Route path={"dashboard"} element={<Dashboard />}>
<Route path={"home"} element={<Home />} />
<Route path={"users"} element={<Users />} />
</Route>
You can render an Index route to render some content when the path equals that of the parent route.
Example:
<Route path="dashboard" element={<Dashboard />}> // "/dashboard/*"
<Route index element={/* some content */} /> // "/dashboard"
<Route path="home" element={<Home />} /> // "/dashboard/home"
<Route path="users" element={<Users />} /> // "/dashboard/users"
</Route>
If you want a specific nested route to be a "default" then either render it again as the index route or render a redirect to it.
Examples:
<Route path="dashboard" element={<Dashboard />}>
<Route index element={<Home />} />
<Route path="home" element={<Home />} />
<Route path="users" element={<Users />} />
</Route>
or
<Route path="dashboard" element={<Dashboard />}>
<Route index element={<Navigate to="home" replace />} />
<Route path="home" element={<Home />} />
<Route path="users" element={<Users />} />
</Route>

How to use useMatch and useResolvedPath to validate non exactly match?

I'm creating an aplication with any routes and sub routes. This aplication has a SideBar with link to routes(pages) and this routes(pages) has links to subroutes(subpages). I want to set active class when the link match(non exactly), example:
links:
/users
/teams
/settings
(/teams/name-of-team/squads) => /teams OK!
(/users/teams/234) => /users OK!
Now, i'm using react router dom v6v example(https://stackblitz.com/github/remix-run/react-router/tree/main/examples/custom-link?file=src%2FApp.tsx) but this return true only when match exactly!
The routes:
<BrowserRouter>
<Routes>
<Route path="status" element={<Status />} />
<Route path="login" element={<Login />} />
<Route path="forgot-password" element={<ForgotPassword />} />
<Route path="reset-password/:token" element={<ResetPassword />} />
<Route path="/" element={<LoggedArea />}>
{/* Inicio */}
<Route index element={<Personal />} />
{/* Dashboards */}
<Route path="dashboards">
<Route index element={<Dashboards />} />
</Route>
{/* Vagas */}
<Route path="jobs">
<Route index element={<Jobs />} />
<Route path=":name" element={<Jobs />} />
</Route>
{/* Documentos */}
<Route path="documents">
<Route index element={<Files />} />
<Route path="*" element={<Files />} />
</Route>
{/* Usuários */}
<Route path="users">
<Route index element={<Users />} />
<Route path="create" element={<CreateUser />} />
<Route path=":name" element={<User />} />
</Route>
{/* Times */}
<Route path="teams">
<Route index element={<Teams />} />
<Route path=":name" element={<Team />}>
<Route index element={<Heading3>Resumo</Heading3>} />
<Route path="overview" element={<Heading3>Resumo</Heading3>} />
<Route path="goals" element={<TeamGoals />} />
<Route path="squads" element={<TeamSquads />} />
<Route path="settings" element={<TeamSettings />} />
</Route>
</Route>
{/* Componentes */}
<Route path="ui">
<Route index element={<Ui />} />
</Route>
{/* Configurações */}
<Route path="settings" element={<Settings />}>
<Route index element={<ProfileSettings />} />
<Route path="profile" element={<ProfileSettings />} />
<Route path="security" element={<SecuritySettings />} />
</Route>
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
My custom link component:
interface SideMenuItemProps {
icon : React.ReactNode;
label: string;
url: string;
tooltip?: boolean;
}
export function SideMenuItem(props: SideMenuItemProps) {
const resolved = useResolvedPath(props.url)
const match = useMatch({
path: resolved.pathname,
end: true
})
return(
<li className={styles.item}>
<Tooltip disabled={!props.tooltip} label={props.label} >
<Link to={props.url} className={`${styles.link} ${match ? styles.active : ''} `}>
{props.icon}
</Link>
</Tooltip>
</li>
)
}

React Router with Context

I'm wrapping some private routes with a context, but for some reason it doesn't move to the next route in the switch.
export const Routes = () => (
<Switch>
<Route exact path="/" component={Home} />
<Route path="/seller/:userName" component={userProfile} />
<Route path="/allproducts" component={AllProducts} />
<Route path="/privacy" component={Privacy} />
<Route path="/terms" component={Terms} />
<Route path="/contact" component={Contact} />
<Route path="/about" component={About} />
<Route path="/learnmore" component={LearnMore} />
<Route path="/faq" component={FAQ} />
<PublicRoute path="/login" component={Login} />
<PublicRoute path="/signup" component={SignUp} />
<PublicRoute path="/reset" component={ForgotPassword} />
<PublicRoute path="/resetToken" component={ForgotPasswordToken} />
<PrivateRoute exact path="/userprofile" component={UserDashboard} />
<PrivateRoute exact path="/submitplate" />
// This works but doesn't allow the router to move to the next potential route.
<BasketProvider>
<PrivateRoute exact path="/checkout" component={Checkout} />
</BasketProvider>
// This never gets reached.
<Route component={NoMatchPage} />
</Switch>
);
Just wondering if theres a better way to go around this? Is this bad practice?
Does it work if you do this?
<PrivateRoute exact path="/checkout" component={() => (
<BasketProvider>
<Checkout />
</BasketProvider>
)} />

How can React-Router-Dom v6 properly distribute internal routers among components?

There is routing at the top level with internal routing, the question arose to add routing inside components such as ProductsPage, ElementsPage, etc.
<BrowserRouter>
<Routes>
<Route path='/' element={<PageLayout />}>
<Route path='marketplace'>
<Route path='products' element={<ProductsPage />} />
<Route path='constituents' element={<ElementsPage />} />
<Route path='resources' element={<ResourcesPage />} />
<Route path='shopping' element={<ShoppingPage />} />
</Route>
<Route path='resource-center'>
<Route path='planner' element={<>планирование</>} />
<Route path='resources' element={<>resources</>} />
</Route>
<Route path='*' element={<>Страница не найдена 404</>} />
</Route>
</Routes>
</BrowserRouter>
The question is how to do this in version 6. Because before version five, you could easily throw a switch into a component a la ProductsPage and specify routes in the switch
You can name all pages explicitly.
<BrowserRouter>
<Routes>
<Route path='/' element={<PageLayout />} />
<Route path='/marketplace/products' element={<ProductsPage />} />
<Route path='/marketplace/constituents' element={<ElementsPage />} />
<Route path='/marketplace/resources' element={<ResourcesPage />} />
<Route path='/marketplace/shopping' element={<ShoppingPage />} />
<Route path='/resource-center/planner' element={<планирование />} />
<Route path='/resource-centerresources' element={<resources/>} />
<Route path='*' element={<Страница не найдена 404/>} />
</Routes>
</BrowserRouter>

Categories

Resources