I tried adding a trailing ? to a route using the v6 router, but it didn't seem to work.
<Route path='/page/:friendlyName/:sort?' element={<Page/>} />
Are optional parameters supported in v6, or are they coming later?
We don't plan on supporting them in v6.
@timdorr Thanks - could you explain a little on how you would achieve it in v6? At the moment I have the below which works but seems less than optimal. Any thoughts?
<Route path='/page/:friendlyName/:sort' element={<Page/>} />
<Route path='/page/:friendlyName/' element={<Page/>} />
It would be great if this could be described in the migration guide – or if there was at least a hint. So the recommended way of doing "optional" params really is ...
<Route path='/page/:friendlyName/:sort' element={<Page/>} />
<Route path='/page/:friendlyName/' element={<Page/>} />
... ?
@gopeter Yes, or you can do something like this:
<Route path="/page/:friendlyName">
<Route path=":sort" element={<Page />} />
<Route path="" element={<Page />} />
</Route>
Aaaaah, great, thank you very much! 😄
@MeiKatz @timdorr my problem with the approach above is that the <Page> component unmounts and mounts again. Performance-wise this might be a bad thing, but in my case it also results in a bunch of refetching of data. I can fix this inside the Page-component itself by checking if data is there already, but not only does this change break my routing, it also breaks application itself.
This is my use case;
<Route path="tickets">
<Routes>
<Route path="archive">
<Route path=":ticketId/:content" element={<List />} />
<Route path=":ticketId" element={<List />} />
<Route path="/" element={<List />} />
</Route>
<Route path="view/:ticketId">
<Route path=":content" element={<List />} />
<Route path="/" element={<List />} />
</Route>
<Route path=":ticketId">
<Route path=":content" element={<List />} />
<Route path="/" element={<List />} />
</Route>
<Route path="/" element={<List />} />
</Routes>
</Route>
A user starts at /tickets, then clicks on a link on the list that navigates to /tickets/1. This now re-renders the complete page where before it would re-render a part inside the component. Navigating from /tickets/1 to /tickets/2 works as expected.
Any other suggestions on how to implement this (Route-wise) without having to refactor the complete <List/>-component?
@robbinjanssen Have you thought about using the <Outlet /> element?
<Route path="tickets" element={ <TicketsPage /> }>
<Route path=":ticketId" element={ <ShowPage /> } />
<Route path="" element={ <IndexPage /> } />
</Route>
const TicketContext = React.createContext( {} );
function TicketsPage() {
const [ tickets, setTickets ] = useState({});
useEffect(() => {
// do some loading stuff
const res = await fetch("/tickets");
const tickets = await res.json();
setTickets( tickets );
}, []);
return (
<Fragment>
<h1>My Tickets</h1>
<TicketContext.Provider value={ tickets }>
<Outlet />
</TicketContext.Provider>
</Fragment>
);
}
function ShowPage() {
const tickets = useContext( TicketContext );
const { ticketId } = useParams();
const ticket = tickets[ ticketId ];
return (
<div>{ JSON.stringify( ticket ) }</div>
);
}
@MeiKatz not yet, hoped I would not have to refactor that ticket page, but seems like there's no other way. It's a pretty "old" component that requires a lot of work when refactoring. So I wish I could somehow keep the optional parameters :)
@robbinjanssen Understandable. But I don't think that there is any other way you can solve it. And I also think, that it is a clean way to do it. Also we could think about dropping the whole context stuff and pass the parameters to the <Outlet /> and from there to the element.
For now I'll just parse the "raw" params into the bits I need, those URLs are not that complicated fortunately, and i'll put the component on the refactor list. Thanks :)