Render same component for 3 routes - react-router

I want my react router to return component only when URL matches either of those 3 paths exactly and return an error when it doesn't. How can I shorten this?
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Table entries={posts} />} />
<Route path="/evens" element={<Table entries={posts} />} />
<Route path="/odds" element={<Table entries={posts} />} />
<Route ??? element={<ErrorPage />} />
</Routes>
</BrowserRouter>
);

RRDv6 routes take only a string path prop. If you need to render the same component on multiple paths you need to render a Route for each.
To make the code a little more DRY you could try mapping the routes from an array of paths.
Example:
return (
<BrowserRouter>
<Routes>
{["/", "/evens", "/odds"].map(path => (
<Route
key={path}
path={path}
element={<Table entries={posts} />}
/>
)}
<Route path="*" element={<ErrorPage />} />
</Routes>
</BrowserRouter>
);
Now whether or not this is more readable or maintainable is likely up for debate/opinion. It is less repetitive though.

Related

Transition between routes in react-router-dom v6.3

So I´m currently refactoring a website, and so I do with the rrd, which was on v5 in the previous website version.
Now, that the component doesn´t exist anymore we have to work with the new component as you probably know.
I previously used framer-motion to transition in and out between the routes like so:
<Switch location={location} key={location.pathname}>
<motion.div
initial="initial"
animate="in"
exit="out"
variants={pageVariants}
transition={pageTransition}>
<Route path="/audit" component={Audit} />
<Route exact path="/smartx" component={SmartX} />
<Route path="/smartx/erc20" component={TokenGenerator} />
<Route path="/createAudit" component={PaymentStatus} />
<Route path="/faq" component={FAQ} />
<Route path="/support" component={Support} />
<Route path="/terms" component={Terms} />
<Route path="/policy" component={Policy} />
<Route path="/about" component={About} />
<Route exact path="/">
<Redirect to="/audit" />
</Route>
</motion.div>
</Switch>;
Simply replacing the Switch component with the Routes component won´t work, since you can only have Route components as childs from .
Moving the <motion.div> one layer up over the Routes component leads to only one initial fade in transition on page load.
new (not quiet working version):
<AnimatePresence>
<PageLayout>
<motion.div
initial="initial"
animate="in"
variants={pageVariants}
transition={pageTransition}>
<Routes>
<Route path="/audit" element={<Audit />} />
<Route path="/smartx" element={<SmartX />} />
<Route path="/faq" element={<FAQ />} />
<Route path="/support" element={<Support />} />
<Route path="/terms" element={<Terms />} />
<Route path="/policy" element={<Policy />} />
<Route path="/about" element={<About />} />
</Routes>
</motion.div>
</PageLayout>
</AnimatePresence>;
Framer motion animations (equalin both old and new version):
const pageVariants = {
initial: {
opacity: 0
},
in: {
opacity: 1
},
out: {
opacity: 0
}
};
const pageTransition = {
type: 'tween',
ease: 'linear',
duration: 0.5
};
Any ideas on how to achieve a transition on each route switch?
Thanks in advance and cheers!
I think your solution is close to working. Move the PageLayout component and motion.div into a layout route that uses the current path as a React key.
Example:
import { Outlet } from 'react-router-dom';
const AnimationLayout = () => {
const { pathname } = useLocation();
return (
<PageLayout>
<motion.div
key={pathname}
initial="initial"
animate="in"
variants={pageVariants}
transition={pageTransition}
>
<Outlet />
</motion.div>
</PageLayout>
);
};
...
<Routes>
<Route element={<AnimationLayout />}>
<Route path="/audit" element={<Audit />} />
<Route path="/smartx" element={<SmartX />} />
<Route path="/faq" element={<FAQ />} />
<Route path="/support" element={<Support />} />
<Route path="/terms" element={<Terms />} />
<Route path="/policy" element={<Policy />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<Navigate to="/audit" replace />} />
</Route>
</Routes>

is there a way to set a default route with React-Router v6

I just can't find a way to set a default route with react-router v6
Is it because it's not good programming anymore?
Can somebody tell me why?
Thanks in advance
Rafael
If I understand your question about a "default" route correctly then I am interpreting this as one of the following:
Use an index route:
You can wrap a set of routes in a layout route and specify an index route:
<Routes>
<Route path="/*">
<Route index element={<ComponentA />} />
<Route path="pathB" element={<ComponentB />} />
<Route path="pathC" element={<ComponentC />} />
</Route>
</Routes>
The index route is the route that will be matched and rendered when the path exactly matches the root parent route's path.
Redirect to a "default" route if no other routes match:
You can also render a redirect to the route you consider to be the "default" route.
<Routes>
<Route path="/pathA" element={<ComponentA />} />
<Route path="/pathB" element={<ComponentB />} />
<Route path="/pathC" element={<ComponentC />} />
<Route path="*" element={<Navigate to="/pathA" replace />} />
</Routes>
TLDR;
use <Route index element={<Navigate to="/dashboard" />} />
index: default computed route.
<Navigate to="whatever you want"/>: is used to navigate to a another already declared path.
LR;
I found an easy way to redirect to a default component using index & Navigate combined.
In my situation I had used React Router V6.6.2 with:
createBrowserRouter(
createRoutesFromElements(...))
The routes look like this
/* All imports go here */
const router = createBrowserRouter(
createRoutesFromElements(
<Route element={<AuthLayout />}>
<Route element={<RrotectedLayout />}>
<Route path="/" element={<MainLayout />}>
<Route index element={<Navigate to="/dashboard" />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="projects" element={<Projects />} />
<Route path="users" element={<Users />} />
<Route path="notifications" element={<Notification />} />
<Route path="settings" element={<Settings />} />
<Route
path="*"
element={<Navigate to="/dashboard" replace={true} />}
/>
</Route>
</Route>
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login />} />
</Route>,
),
{},
)
export default function App() {
return (
<>
<RouterProvider router={router} />
</>
)
}
Now when you access your application, React router will figure out which index your application needs to point to, and since your index contains a Navigation to a specific path, you'll be redirect to that path by default. you don't need to specify a specific component (element) in this situation because you don't wanna loose the link to it.
I actually found the answer here but I just wanna share my solution if it helps someone with theirs.
You can set path='*' to make a default route. The index route deals a parent route ("/") but doesn't deal with routes which should otherwise return a 404 status.
if (!token) {
// This router will handle my public routes. Anything else is going to redirect to AuthPage without losing the previous route typed.
return (
<BrowserRouter>
<Routes>
{/* Auth */}
<Route path="/">
<Route exact path="recover" element={<UnknownPage />} />
// Default route
<Route path="*" element={<AuthPage setToken={setToken} />} />
</Route>
</Routes>
</BrowserRouter>
);
}
// This router is inside my application. Only logged users will get here.
return (
<BrowserRouter>
<Routes>
{/* My base page is just some fixed structure like Header, Sidebar and Footer. For this problem you can ignore it. */}
{/* BasePage */}
<Route path="/*" element={<BasePage logout={logout} />}>
{/* This is my specific users route */ }
{/* Users */}
<Route path="users">
<Route path="" element={<UsersPage />} />
<Route path=":id" element={<UserInfoPage />} />
</Route>
{/* Anything else is going to show this page. Even random words like: http:localhost:3000/anything-asdvasd */}
{/* Default Route */}
<Route path="*" element={<UnknownPage />} />
</Route>
</Routes>
</BrowserRouter>
);
Using parent routes like I used in my users routes makes it easier to scope your default routes.
If you are using createBrowserRouter you can set the default route in following way.
As per docs component loads children of parent. So
const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "/",
element: <Home />,
},
{
path: "/home",
element: <Home />,
},
],
},
],);
If you are using createBrowserRouter you can set the default route in following way.
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{ index: true, element: <Navigate to="/calculation" replace /> },
{ path: "calculation", element: <Calculation /> },
{ path: "calendar", element: <Calendar /> },
{ path: "profile", element: <Profile /> },
],
},
]);

How to set a sublink in react router

I am attempting to use react router to do a url like so:
example.com/admin/members/{anyid}
If this url is hit with the id it would display user info with that id.
My code:
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
<BrowserRouter>
<Switch>
<Route path="/admin" render={props => <AdminLayout {...props} />} />
<Route path="/auth" render={props => <AuthLayout {...props} />} />
<Redirect from="/" to="/admin/index" />
</Switch>
</BrowserRouter>,
</FirebaseContext.Provider>,
document.getElementById("root")
);
I have attempted to do this:
<Switch>
<Route path="/admin" render={props => <AdminLayout {...props} />} />
<Route path="/auth" render={props => <AuthLayout {...props} />} />
<Route path="/admin/members/:id" component={SavedMemberForm} />
<Redirect from="/" to="/admin/index" />
</Switch>
My assumption was that /admin/members/:id would over ride any children urls in admin. This is not the case when I hit /admin/members/1234 it reads it as if I'm just going to /admin
How can I get it to achieve my desired result?

React Router 4 not rendering 404 on routes not found

I'm working on a React app that is using React Router 4. All of my routes are working great, however, if I go to a route that is not on the list I am not getting my 404 page. Any idea what I'm missing?
I'm using React 16 and React Router 4. This is for a sample app like Indeed.
export default function App() {
const companyRoutes = () => (
<Main>
<Route exact path="/companies/new" component={NewCompanyPage} />
<SubNav>
<PageBody companyPages>
<Switch>
<Route exact path="/companies" component={CompanyPage} />
<Route path="/companies/:companyId/edit" component={EditCompanyPage} />
<Route path="/companies/:companyId/jobs/:jobId/edit" component={EditJobPage} />
<Route path="/companies/:companyId/jobs/new" component={NewJobPage} />
<Route path="/companies/:companyId/jobs" component={CompanyJobsPage} />
<Route path="/companies/:companyId/locations" component={CompanyLocationsPage} />
<Route path="/companies/:companyId/recruiters" component={CompanyRecruitersPage} />
<Route path="/companies/:companyId/settings" component={CompanySettingsPage} />
<Route path="/companies/:companyId/applicants" component={CompanyApplicantsPage} />
</Switch>
</PageBody>
</SubNav>
</Main>
)
const jobRoutes = () => (
<Main>
<PageBody>
<Switch>
<Route exact path="/jobs" component={JobsPage} />
<Route path="/jobs/:jobId" component={JobPage} />
<Route path="/jobs/:jobId/apply" component={NewApplicationPage} />
</Switch>
</PageBody>
</Main>
)
const profileRoutes = () => (
<Main>
<SubNav>
<PageBody>
<Switch>
<Route exact path="/profiles" component={ProfilePage} />
<Route path="/profiles/:profileId/resume" component={ResumePage} />
<Route path="/profiles/:profileId/edit" component={EditProfilePage} />
<Route path="/profiles/:profileId/applications" component={ApplicationsPage} />
<Route path="/profiles/:profileId/settings" component={ProfileSettingsPage} />
</Switch>
</PageBody>
</SubNav>
</Main>
)
const loginRoutes = () => (
<LoginMain>
<Switch>
<Route exact path="/login" component={LoginPage} />
<Route exact path="/sign_up" component={LoginPage} />
</Switch>
</LoginMain>
)
const MainRoutes = () => (
<div>
<Route path="/companies" component={companyRoutes} />
<Route path="/jobs" component={jobRoutes} />
<Route path="/login" component={loginRoutes} />
<Route path="/profiles" component={profileRoutes} />
</div>
)
return (
<BrowserRouter>
<div>
<Route path="/" component={MainRoutes} />
<Route path="/404" component={NotFoundPage} />
</div>
</BrowserRouter>
)
}
[UPDATE]: Here you will find a proper, better tested example.
Not tested but try:
return (
<BrowserRouter>
<Switch>
<Route path="/" component={MainRoutes} />
<Route component={NotFoundPage} />
</Switch>
</BrowserRouter>
)
The idea is that inside a Switch, the router will try every route from the first one to the last one until it finds a corresponding path.
By having <Route component={NotFoundPage} /> at the very bottom of your routing, with no path specified, it will act as a wildcard, catching all unmatched urls.

React-routing config issue to change new home page

I am new to react-router.
In current app we are using below react-router
module.exports = (
<Router history={HashHistory}>
<Route path="/" component={Frame}>
<IndexRoute component={Page1} />
<Route path="all" component={Page2} />
<Route path="admin" component={Page3} />
<Route path="proxy" component={Page4} />
</Route>
</Router>
);
due to some changes now I want to make different page as home page but also want to make minimum changes to unimpact the current functionalities. Using the below router config but not working
<Router history={HashHistory}>
<Route path="/" component={Home}>
<Route path="achieve" component={Frame}>
<Route path ="achieve" component={Page1}>
<Route path="all" component={Page2} />
<Route path="admin" component={Page3} />
<Route path="proxy" component={Page4} />
</Route>
</Route>
</Route>
</Router>
Any pointer to resolve the issues and to explore this?
Thanks in advance.
If you wants to make each page as a home page then don't use nested route, make the separate route for each.
Try this:
<Router history={HashHistory}>
<Route path="/" component={Home}/>
<Route path="/achieve" component={Frame}/>
<Route path ="/achieve" component={Page1}/>
<Route path="/all" component={Page2} />
<Route path="/admin" component={Page3} />
<Route path="/proxy" component={Page4} />
</Router>
Use nesting in that route where you want to use some component inside that. Lets say you want to use some component inside admin page then :
<Router history={HashHistory}>
<Route path="/" component={Home}/>
<Route path="/achieve" component={Frame}/>
<Route path ="/achieve" component={Page1}/>
<Route path="/all" component={Page2} />
<Route path="/admin" component={Page3} >
<IndexRoute component={comp1}/>
<Route path="/xyz" component={comp2}/>
</Route>
<Route path="/proxy" component={Page4} />
</Router>
Follow these links for better explanation:
https://css-tricks.com/learning-react-router/
https://medium.com/#dabit3/beginner-s-guide-to-react-router-53094349669#.sjzpetwbb
Please comment if need any help.