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 />
);
};
Related
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.
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 /> }
]
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
Suppose we have the following routes:
{
path: 'a',
component: AComponent,
children: [
{
path: '',
component: BComponent
},
{
path: '',
component: CComponent,
children: [
{ path: '', component: DComponent }
]
}
]
}
And the following URL is pasted into the browser's address bar:
http://localhost:4200/a
Questions
How does the Router know what component to display?
Would all the four components (A, B, C, D) be displayed?
Where would each component be displayed?
Does every parent component always have its own RouterOutlet, so each component along a route of parent/child/grand-child/etc. gets displayed inside its parent's respective RouterOutlet?
Usually, when displaying a route with child routes, each component is displayed inside its parent RouterOutlet. But, if only AComponent had a RouterOutlet, where would BComponent, CComponent and DComponent be displayed?
Given that you aren't getting any sort of error the router will give you the first matching route it found. In this case BComponent. Only one component can be shown in a router outlet (to do otherwise you need something like auxRoute).
If CComponent had a route like 'c' you could access it from the route http://localhost:4200/a/c then you would get CComponent with DComponent in CComponents router outlet.
Hope that helps.
My router in configured as follows. It works and does what it's supposed to.
import Demo1 from "../vuex_modules/demo/demo1.vue"
import Demo2 from "../vuex_modules/demo/demo2.vue"
export const routes = [
{ path: "/demo/demo1", component: Demo1 },
{ path: "/demo/demo2", component: Demo2 }
];
Now, I need to match me some query strings. When I click in one of the views routed to above, I want the object pushed to the router to look like this.
export default {
methods: {
clicky: function(row) {
this.$router.push({ path: "", query: { id: row } });
}
}
}
I want the new URL, with ?id=123 added, to lead to another page (while demo2.vue is the table view, demo2_id.vue is supposed to be displayed upon a click and present details for the particular row being clicked.
According to Vue router docs, I'm suppose to add a colon when a part of URL is dynamic. I've tried different approaches, including the one below. I'm not routed to the page requested, though. Instead, I dwell still on the original page.
import Demo1 from "../vuex_modules/demo/demo1.vue"
import Demo2 from "../vuex_modules/demo/demo2.vue"
import Demo2_Id from "../vuex_modules/demo/demo2_id.vue"
export const routes = [
{ path: "/demo/demo1", component: Demo1 },
{ path: "/demo/demo2", component: Demo2 },
{ path: "/demo/demo2?:id", component: Demo2_Id }
];
Goolearching for vue router query strings leads to nothing that I can regard as useful (possibly due to ignorance)...
Case 1:
Following routes are two same route:
{ path: "/demo/demo2", component: Demo2 },
{ path: "/demo/demo2?:id", component: Demo2_Id }
Case 2:
While following are different:
{ path: "/demo/demo2", component: Demo2 },
{ path: "/demo/demo2/:id", component: Demo2_Id }
In first case: /demo/demo2?:id=213, you can get id as $route.query.id while in second case: /demo/demo2/:id, you will get id as $route.params.id.
Now if you want to have routes as in case 1: You will have single row in routes file and single route:
{ path: "/demo/demo2", component: Demo2 },
and you can write code to detect whether $route.query.id is present or not and load component accordingly with use of v-if
If you want to have routes as in case 2: you can add above two lines in routes file and treat them as two different routes.