Add optional query parameters to a dynamic path using React Router - reactjs

I'm trying to add an optional query parameter to the end of a path, so the URL woukd look like this: /user/1/cars?makeYear=2020 or /user/1/cars. The relevant Route is defined as follows. I'm unable to find guidance on how to add an optional query parameter to an existing path. For example, the following doesn't work:
<Route path="user" element={<UserScreen />}>
<Route path=":id/makeYear?" element={<User/>} />
</Route>
Here I'd think that <Route path=":id/makeYear?" element={<User/>} /> will mark makeYear as an optional parameter, but no, doesn't work.
I then thought that I'd access the query parameters directly in the component, so given that the URL is /user/1/cars?makeYear=2020, I can fetch the URL via the useLocation api provided by react-router. However, the query parameter, however this doesn't work either as the query parameter is immediately removed from the URL (I'm guessing by react-router...).
I'm using react-router-dom (6.2.2)

react-router-dom doesn't use the queryString for route path matching. Remove the queryString part from the route path prop. Access the query params in the component via the useSearchParams hook.
<Route path=":id" element={<User/>} />
...
import { useSearchParams } from 'react-router-dom';
const User = () => {
const [searchParams] = useSearchParams();
const makeYear = searchParams.get("makeYear");
// handle logic based on makeYear
...
};

Related

How can I add an indefinite amount of parameters in react router dom v6? [duplicate]

Trying to create a file renderer but I do not know how to create in a right way. The snippet that I have is that one but is super repetitive:
<Routes>
<Route path='/explorer' element={<Files>}>
<Route path=':root' element={<Files>}>
<Route path=':branch' element={<Files>}>
<Route path=':leaf' element={<Files>} />
...
</Route>
</Route>
</Route>
</Routes>
Examples:
/explorer/home
/explorer/home/username
/explorer/home/username/documents
...
If I use useParams hook from react-router-dom sometimes some params would be undefined and I would like to ignore these params (looping all params I could do it but I do not think is the best practise)
With that params after I create an array and make a request to display all the files or the folders of the selected path (/explorer/home/username)
Is it some way to set a generic number of params for just one component and get a params object with just the need it params?
<Routes>
<Route path='/explorer' element={<Files>}>
<Route path='??' element={<Files>}>
</Route>
<Routes>
Just a suggestion I have for a simple way to manage this would be to render a single route with no path parameters and a trailing wildcard character "*" to continue matching after the first path segment.
Example:
<Routes>
<Route path="/explorer/*" element={<Files />} />
</Routes>
The Files component will then access the entire location.pathname and apply a little string manipulation to get the file/directory structure from the URL path segments.
Example:
const Files = () => {
const { pathname } = useLocation();
const path = pathname
.slice(1) // remove leading "/"
.split("/") // split path directories
.slice(1); // remove leading "explorer" route path
return (
...
);
};
pathname
path array
/explorer/home
["home"]
/explorer/home/username
["home", "username"]
/explorer/home/username/documents
["home", "username", "documents"]
/explorer/home/username/documents/math/exercises
["home", "username", "documents", "math", "exercises"]
What you do with path from here is up to you.
The other solution I'd proposed was to pass the path as a query parameter, i.e. "/explorer?path=/home, and apply a similar path string processing. Perhaps something like the following:
const [searchParams] = useSearchParams();
const stringPath = searchParams.get('path');
const path = stringPath
.slice(1) // remove leading "/"
.split("/"); // split path directories

Passing Route path to the children element

<Route path="/pointandclick">
<MyComponent />
</Route>
For this piece of code, is there any way for my component to get the path of the Route that has been hit?
edit: to be more precise, let's say I want to know the string that has been hit (in this case /pointandclick) because in MyComponent I want to route between other paths, so I have to know if which path do I come from.
E.g.
<Route path="/pointandclick">
<MyComponent />
</Route>
<Route path="/draggablegame">
<MyComponent />
</Route>
and in my component I want to route on other components depending on the path. (example: if the Route that has been hit is pointandclick I want to render between game1, game2, game3 and if the Route is draggablegame I want to render between drag1, drag2, drag3 - so using the location hook might not be the best thing I think.
You're looking for a simple javaƛcript's window.location.pathname.
The useLocation hook returns the location object that represents the current URL. You can think about it like a useState that returns a new location whenever the URL changes.
import { useLocation } from 'react-router-dom'
function MyComponent() {
let location = useLocation();
console.log(location);
}
With useLocation(), you can get the active route. It's a hook that returns the location object that contains information about the current URL. Whenever the URL changes, a new location object will be returned.
Demo: https://codesandbox.io/s/use-location-demo-7d3c3
Read on: https://www.kindacode.com/article/react-router-uselocation-hook-tutorial-and-examples/

React router two URL parameters &more

I'm using react-router-dom and this is currently how it looks:
<Switch>
<Route path={"/layouts/:layoutID"} component={Layouts} />
<Route
path={"/dashboard/:dashboardID"}
component={Dashboards}
/>
</Switch>
When the user navigates to "/dashboard/:dashboardID" inside this component he can choose a sub-page onClick, and I want the URL structure will be "/dashboard/:dashboardID/:pageID" pageID will navigate to 'PageIdComponent' this component will get a 'match' props and will show pageID
Please see the attached file that shows the necessary structure.
What is the best way to implement it?
If you have the child route inside your Dashboard component, then you can use the match.path value to build up a sub route:
<Route path={`${props.match.path}/:dashboardId`}>} component={SubDashboard} />
in order to make the path match what the parent's had and then add a new variable on top of that.
Then you can navigate to it using the match.url to make a link to the current URL and add the subPage to it:
<Link to={`${props.match.url}/pageFour`}>Page four</Link>
Instead of prop driling, React Router offers ways to get the relevant props to whatever components you desire via withRouter HOC or various hooks. The hooks were introduced in version 5.1
To get the match via a hook you can use const match = useRouteMatch()
To get the relevant props via the HOC:
const Example = useRouteMatch(function Example({ match, location, history }) {
return <div>{match.url}</div>;
});
For react router v6 (that's upcoming):
https://reacttraining.com/blog/react-router-v6-pre/#nested-routes-and-layouts

Why is my custom hook not re-initialised on path change?

I am using ReactRouter to route the application (BrowserRouter at the top level) with a Switch that includes all the routes.
In my use-case I want to be able to handle paths that include the path-parameters (bedId) and navigate between different sub-paths (i.e. /beds/:bedId/, /beds/:bedId/info/) as well asa case where the path is (/beds/-).
I also want to be able to direct user to a different "bed" while they are already on some bed, so /beds/bed1/info -> /beds/bed2, and so on...
My BedView component is responsible for routing within that /beds/:bedId path like so:
// App.jsx (fragment)
<Switch>
<Route
path="/"
exact
render={() => (<Redirect to="/beds/-"/>)}
/>
<Route
path="/beds/-"
exact
component={SomeOtherComponent}
/>
<Route
path="/beds/:bedId"
component={BedView}
/>
</Switch>
The problem occurs when I try to use a hook that relies on the current path-parameter to fetch the latest data (i.e. call to /beds/bed1 will result in a call to http://myapi.com/beds/bed1/timeseries). The useLatestData hook is called from the BedView component, which look like so:
// BedView.jsx (fragment)
export default function BedView(props) {
const {bedId} = props.match.params;
let {path, url} = useRouteMatch('/beds/:bedId');
const bedData = useLatestData({
path: `/beds/${bedId}/timeseries`,
checksumPath: `/checksum/timeseries`,
refresh: false
});```
if(!bedData){
return <Loading/>;
}
return (
<Switch>
<Route exact path={path}>
<Redirect to={`${url}/info`}/>
</Route>
<Route exact path={`${path}/info`} >
<SomeComponent info={bedData.info} />
</Route>
</Switch>
}
...and the useLatestData hook is available here.
The problem is the fact that upon redirecting from /beds/bed1/info to /beds/bed2/info, the hook does not update its props, even though the BedView component seems to be re-rendering. I have created a version of the hook that 'patches' the problem by adding an useEffect hook in my custom hook, to detect the change in path (as supplied in the function arguments) and set data to null, but then the behaviour changes on the BedView.jsx's end - making the following check fail:
if(!bedData){
return <Loading/>;
}
I'm not entirely sure which part is the culprit here and any guidance would be much appreciated! As far as I'm aware, the hook is no re-initialised because the path change still results in the same component. There is also one caveat, once I change the BrowserRouter to include the forceRefresh flag, everything works fine. Naturally, I don't want my page to refresh with every redirect though...
try this:
const {bedId} = props.match.params;
let {path, url} = props.match;

Get url as object in react

How can we get url as object not string.
This is my sample code below.
App.js
return (
<Switch>
<Route path='/:company/:project/:todo' component={Project} />
<Route path='/:company/:project' component={Project} />
<Route path='/:company' component={Projects} />
</Switch>
)
For example when a url is like companyxyz/project0/todo0. Somewhere in any of the components can get
{
company: companyxyz,
project: project0,
todo: todo0
}
Another example is companyxyz/project0. Then it will create like this.
{
company: companyxyz,
project: project0
}
As the examples above match their corresponding Route and map into object as Route is keys and Url is values
I use useLocation() but it returns a pathname with a url in string. I also use useParams() but returns empty object.
It is useParams() that can give us the expected results. The problem was, I use useParams() inside App.js which on this thread Can useParams be able to use inside App.js? can answer it.
For summary, useParams can only give us the object when we use it except in App.js

Resources