React Router V6 full stop making URL invalid - javascript

Using useRoutes and Outlet. I have the following route example:
const routes = [
{
path: "/",
element: <Dashboard/>,
children: [
{ path: "/*", element: <Profile /> },
{ path: "/*/example", element: <Example/> },
],
}
]
const App= () => {
const route = useRoutes(routes)
return <div>{route}</div>
}
I want to push user_id to the url so for example /user1 this loads the component as expected however when I type something like /firstname.surname I get the follow error Cannot GET /firstname.surname however /firstname.surname/example does load the component
This is due to the full stop in the Id. How can I resolve this and accept it as a valid URL?
When I update path for dashboard to "" it seems to work however when I do something like /foo.bar/test it loads profile component how do I restrict this as this path does not exists?

I think the wildcard in { path: "/*/example", element: <Example/> } doesn't work well with other routes also specifying the wildcard. It's my understanding that the "/*" is valid only at the end of the path to indicate matching more deeply nested routes.
The following config seems to work though, using a named path param.
const routes = [
{
path: "/",
element: <Dashboard />,
children: [
{ path: "/*", element: <Profile /> },
{ path: "/:path/example", element: <Example /> }
]
}
];

const routes = [
{
path: "/",
element: <Dashboard/>,
children: [
{ path: "/:id", element: <Profile /> },
{ path: "/:id/example", element: <Example/> },
],
}
]
const App= () => {
const route = useRoutes(routes)
return <div>{route}</div>
}
"*" is a generic wildcard need to pass id like above

Related

How to use React router v6.4 with typescript properly?

I'm trying to use react-router-dom v6.4+ in my project. I implemented it as a route array of objects. Its worked as routing but suddenly I got another issue realated this. I can't call any hook inside the Component which located on element property in route array.
In the route.ts file:
import MainLayout from './container/layouts/mainLayout/MainLayout'
import ErrorPage from './view/Error'
import Home from './view/Home'
const routes: RouteObject[] = [
{
path: '/',
element: MainLayout(),
children: [
{
index: true,
element: Home(),
},
],
},
{
path: '*',
element: ChangeRoute('/404'),
},
{
path: '/404',
element: ErrorPage(),
},
]
const router = createBrowserRouter(routes)
export default router
and in the app.ts file:
<RouterProvider router={router} fallbackElement={<React.Fragment>Loading ...</React.Fragment>} />
But If I try to use any hook , inside MainLayout component , its saying
code in MainLayout component :
const MainLayout = () => {
const [collapsed, setCollapsed] = useState(false)
return (
<Layout className='layout'>
<SideBar collapsed={collapsed} />
<Layout>
<Topbar collapsed={collapsed} setCollapsed={setCollapsed} />
<Outlet />
</Layout>
</Layout>
)
}
export default MainLayout
I think if I use element: <MainLayout/> instead of element: MainLayout(), then this issue will resolve. but typescript doesnt allow me to do this. and on the documentation every thing is on plain javascript. only one type defination there is this
How to solve this? Kindly guide me.
Edit
Here is the codesandbox demo : visit sandbox
Changes the name of the route.ts file to route.tsx, now you can will set components in the element object property, this works for me.
The element prop expects a React.ReactNode, you are directly calling a React function instead of passing it as JSX.
Example:
const routes: RouteObject[] = [
{
path: '/',
element: <MainLayout />,
children: [
{
index: true,
element: <Home />,
},
],
},
{
path: '*',
element: <ChangeRoute redirect='/404' />,
},
{
path: '/404',
element: <ErrorPage />,
},
]

How can I create a subrouter with React Router v6?

Here is my current React Router implementation:
const router = createBrowserRouter([
{
path: "/",
element: (
<Page activeNav="home" >
<Home />
</Page>
)
},
{
path: "/about",
element: (
<Page activeNav="about" >
<About />
</Page>
)
},
{
path: "/blog",
element: (
<Page activeNav="blog">
<Blog />
</Page>
)
},
{
path: "/blog/:postName",
element: (
<Page activeNav="blog" >
<Post />
</Page>
),
loader: ({ params }) => params.postName
},
{
path: "/chess",
element: <ChessRouter />
}
])
The last route, /chess is of importance. I am looking to define routes such as /chess/play, /chess/login, /chess/register, etc. My initial idea was to just put another Router as the element for the /chess path and then all those paths would be routed from there. However, that throws an error saying:
You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
I also tried using the children property on the /chess route but this does not render anything when I go to /chess/play etc.
What is the correct way of implementing subpaths (not sure of the correct word for it)?
It is correct that you cannot render a router component within another router component as this is an invariant violation. You need only one router and routing context per React app.
To render sub-routes on "/chess" then there are two options:
Render nested routes in the routes configuration declaration. This requires the ChessRouter component to render an Outlet component for nested routes to render their element content into. Nested routes will be able to use the new RRDv6.4 Data APIs.
const router = createBrowserRouter([
...,
{
path: "/chess",
element: <ChessRouter />,
children: [
...,
{
path: "play",
element: <ChessPlay />
},
... other chess sub-rotues
],
}
]);
const ChessRouter = () => {
...
return (
...
<Outlet />
...
);
};
Render a root route with trailing wildcard ("*") character that allows descendent routes to also be matched. This allows the ChessRouter component to render descendent routes, i.e. a Routes component with a set of Route components. Descendent routes will not be able to use the RRDv6.4 Data APIs.
const router = createBrowserRouter([
...,
{
path: "/chess/*",
element: <ChessRouter />,
}
]);
const ChessRouter = () => {
...
return (
...
<Routes>
...
<Route path="/play" element={<ChessPlay />} />
... other chess sub-rotues
</Routes>
...
);
};
If your ChessRouter does not contain any additional functionality besides route declarations, you could drop it altogether and use an index route.
Working off of what Drew had:
const router = createBrowserRouter([
...,
{
path: "/chess",
children: [{
index: true,
element: <ChessPlay /> // The default component to load at '/chess'
},
{
path: "play",
element: <ChessPlay />
},
... other chess sub-rotues
],
}
]);
This will let all of your child routes under /chess work as well as prevent an empty page from showing if a user hits the base /chess route.

React Router v6 routing with paths like https://adomain.com/blogs/sampleblog [duplicate]

This question already has an answer here:
Page layout broken in React Router v6
(1 answer)
Closed 4 months ago.
I've defined nested routes using createBrowserRouter and I expected that the router would route to my child page. However, it seems to stop at the top-level part of the url. BlogsPage and SampleBlog are both React components.
I expected "https://adomain/blogs/sampleblog" to get routed to SampleBlog not to BlogsPage. I thought I could nest as deeply as I liked and that the router would match the longest matching path and invoke that component.
const router = createBrowserRouter([
{
path: "/",
element: <App />,
errorElement: <ErrorPage />,
children: [
{ path: "", element: <HomePage /> },
{ path: "home", element: <HomePage /> },
{
path: "blogs",
element: <BlogsPage /> },
children: [
{ path: "sampleblog", element: <SampleBlog /> },
]
},
]
},
]);
children are used to render child-routes. You would need to use an <Outlet /> inside BlogsPage
What you wanted to do is creating two routes at the same level
[
{ path: "blogs", element: <BlogsPage /> },
{ path: "blogs/sampleblog", element: <SampleBlog /> }
]

React Router V6.4 - Not rendering nested route element - instead render parents

I am testing React Router v6.4 with CreateBrowserRoute
Apparently, I'm running into a problem when I nest the routes deeper than 2 levels
Router Object
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
children: [
{
index: true,
element: <Index/>
},
{
path: "tasks",
element: <TaskIndex/>,
children: [
{
index: true,
element: <TaskQue/>
},
{
path: "task-que",
element: <TaskQue/>,
children: [
{
path: "dashboard",
element: <TaskDashboard/>,
},
]
},
]
},
],
},
]);
Basically, the path causing troubles is this path tasks/task-que/dashboard if I understand it all correctly it should map it like this tasks->task-que->dashboard(element) and then render the element set as the element key-value pair.
The route is working(ish), because if I remove the path: "dashboard" route and visit tasks/task-que/dashboard it will fail.
It seems a bit odd as it works very well in the second-level nesting.
If i change the parents element:
path: "task-que",
element: <TaskQue/>,
To
path: "task-que",
element: <TaskDashboard/>,
It will use TaskDashboard at both of these routes:
/tasks/task-que
/tasks/task-que/dashboard
Seems like I'm misunderstanding something or missing something, does anyone have any knowledge about deeper react-router nesting who can provide constructive tips or point out where I'm failing in my test?
Seems like the TaskQue component is missing rendering an Outlet component for any nested routes it is wrapping. Each level of routing depth, if wrapping routes to nest them, still needs to render its own Outlet for the nested routes.
const TaskQue = () => {
... logic ...
return (
... Task Queue UI JSX ...
<Outlet /> // <-- "./dashboard" and <TaskDashboard />
);
};

cant access react-router params from parent route

I'm using react-router version 6.2.1. My router is setup like so in a Routes component:
const routes = isLoggedIn => [
{
path: '/',
element: isLoggedIn ? <DashboardLayout /> : <Navigate to={LOGIN} /> ,
children: [
// redirect to homepage on null route (e.g. localhost:3000 with no trailing '/')
{ path: '', element: <Navigate to = {HOME} /> },
{ path: HOME, element: <Home /> },
{ path: LIBRARY,
element: <Library/>,
children: [
{
path: ':itemId',
element: <ItemView/>
}
]
}
}
]
export default function Routes(props) {
const loginStatus = props.loginStatus === LOGGED_IN;
const routing = useRoutes(routes(loginStatus));
return (
<>
{routing}
</>
);
}
I would like to access the itemId param in the url from a component that is in the Library component which is a parent route to the itemId. If i call the useParams hook from that parent route I do not see the itemId param. Why is this the case? Am i using the wrong version of react-router? According to this github pr I believe parent routes should have access to all params:
https://github.com/remix-run/react-router/pull/7963

Categories

Resources