Get url as object in react - reactjs

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

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

Add optional query parameters to a dynamic path using React Router

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
...
};

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/

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;

React Router: Redirecting URLs with a specific param

I'm updating a data repository site where datasets are mapped to an id, which is the param used in our url paths. A few datasets got corrupted recently and part of the solution involved changing their ids. Problem is, a lot of users are linked to datasets on our site - some of which are dead now that those aforementioned ids have changed.
For now, I'm just doing a quick client-side redirect on the 5 or so ids that are dead. I just want to redirect the user from /datasets/oldID to /datasets/newID but I can't find anything in the docs about literally redirecting to a different url. Yep, hardcoding it.
If www.example.com/rootpath/dataset/001 is dead and is now www.example.com/rootpath/dataset/002, how can I redirect the user FROM www.example.com/rootpath/dataset/001 and TO www.example.com/rootpath/dataset/002?
Here's the dataset routes setup
const DatasetRoutes = ({ dataset }) => (
<Switch>
<Route
name="dataset"
exact
path="/datasets/:datasetId"
render={() => <DatasetContent dataset={dataset} />}
/>
<Route
name="download"
exact
path="/datasets/:datasetId/download"
component={DownloadDataset}
/>
<Route
name="publish"
exact
path="/datasets/:datasetId/publish"
component={() => (
<Publish datasetId={dataset.id} metadata={dataset.metadata} />
)}
/>
/* ...
more routes etc
*/ ...
</Switch>
)
I'm kind of baffled that I can't figure out how to do something so presumably simple with React Router v4. I've tried several things...is there a straightforward solution to this?
You can handle the redirect in DatasetContent component:
Set up a dictionary mapping old ids that require redirecting to new ids.
Use the useParams hook (or however you are accessing the params) and in the DatasetContent component:
const map = {
oldId: "newId"
};
let { datatsetId } = useParams();
if (map.hasOwnProperty(datasetId) {
return (<Redirect to={`/datasets/${map[datasetId]}`});
}
// the rest of your original DatasetContent rendering code.
...

Resources