<Route path="users">
<Route path=":id" element={<UserProfile id={":id"} />} />
</Route>
The above is what I am trying to do. The code isn't correct. How to make it correct?
The route path params are located on a params object accessible by the useParams hook.
The useParams hook returns an object of key/value pairs of the
dynamic params from the current URL that were matched by the <Route path>. Child routes inherit all params from their parent routes.
For a given route:
<Route path=":id" element={<UserProfile />} />
The UserProfile component will use the useParams hook to access the id route path param.
Example:
import { useParams } from 'react-router-dom';
...
const UserProfile = () => {
...
const { id } = useParams();
...
};
If the UserProfile component can't use React hooks directly for some reason and takes id as a prop, then create a wrapper component to use the hook and inject the prop.
Example:
import { useParams } from 'react-router-dom';
...
const UserProfileWrapper = () => {
...
const { id } = useParams();
...
return <UserProfile id={id} />;
};
...
<Route path="users">
<Route path=":id" element={<UserProfileWrapper />} />
</Route>
Related
I'm trying to use useParams() in my App component because I need it in two different child components.
But useParams() returns *: "tenants/rdyTupPulEab6mztoLvnQ/projects/0/workspace" not actually able to destructure the tenantId.
I assume this is because App isn't rerendering when the url changes, but I don't want to put two useParams() in both children and send the data back up to app. This is the best place for it to go, but not sure how to get useParams() to destructure the data correctly.
How can I do this, or what alternatives are there?
MRE:
function App() {
console.log(useParams())
useEffect(() => {
(api call that needs the tenantId from useParams())
})
return (
<Routes>
<Route path="/tenants/:tenantId/workspace"
element={<Workspace/>}/>
<Route path="/tenants/:tenantId/setup" element=.
{<Setup/>}/>
</Routes>
)
}
The console.log returns {*: 'tenants/rdyTupPulEab6mztoLvnQ/projects/0/workspace'}.
I need it to return {*: 'tenants/rdyTupPulEab6mztoLvnQ/projects/0/workspace', tenantId: 'rdyTupPulEab6mztoLvnQ'}
The App component can't access the route path params of any of the routes the Routes component is managing. The options you have are to use the matchPath utility to find a "match" to extract the tenentId parameter value.
Something like:
function App() {
const match = useMatch("/tenants/:tenantId/*");
useEffect(() => {
if (match) {
const { tenantId } = match.params;
// ... business logic using tenentId
}
}, [match]);
return (
<Routes>
<Route path="/tenants/:tenantId/workspace" element={<Workspace />} />
<Route path="/tenants/:tenantId/setup" element={<Setup />} />
</Routes>
);
}
An alternative is to create an intermediate layout component that can use the useParams hook.
Example:
import { Outlet, useParams } from 'react-router-dom';
export const TenantIdLayout = () => {
const { tenantId } = useParams();
useEffect(() => {
if (tenantId) {
// ... business logic using tenentId
}
}, [tenantId]);
return <Outlet />;
};
function App() {
return (
<Routes>
<Route element={<TenantIdLayout />}>
{/* "tenantId" routes */}
<Route path="/tenants/:tenantId/workspace" element={<Workspace />} />
<Route path="/tenants/:tenantId/setup" element={<Setup />} />
</Route>
{/* non-"tenantId" routes */}
</Routes>
);
}
This worked in "react-router-dom": "^5.3.0"
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Api from "./Api";
const api = new Api();
const App = () => {
return (
...
<Router basename="/my-app">
<Switch>
<Route
path="/complete"
render={(props) => <ConfirmationPage {...props} api={api} />}
/>
...
</Switch>
</Router>
After upgrading to "react-router-dom": "^6.4.3"
We've tried:
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Api from "./Api";
const api = new Api();
const App = () => {
return (
...
<Router basename="/my-app">
<Routes>
<Route
path="/complete"
element={(props) => <ConfirmationPage {...props} api={api} />}
/>
...
</Routes>
</Router>
But that doesn't work. We've read through https://reactrouter.com/en/6.4.3/upgrading/v5
but do not see how to handle passing in props.
In react-router-dom#6 the route components are passed as JSX to the element prop, and passing props to the routed component works just like it does anywhere else in React.
Example:
<Router basename="/my-app">
<Routes>
<Route
path="/complete"
element={(
<ConfirmationPage
api={api} // <-- props passed to component
/>
)}
/>
...
</Routes>
</Router>
There are no longer any route props, so if the routed components need access to what was previously provided they will need to use the React hooks, i.e. useLocation, useNavigate, useParams, etc.
Additional documentation:
Why does <Route> have an element prop instead of render or component?
Advantages of <Route element>
In react router V6, we write the routes in this fashion-
<BrowerRouter>
<Routes>
<Route path="..." element={<div> ... </div>} />
<Route path="..." element={<div> ... </div>} />
</Routes>
</BrowerRouter>
Now if I want to insert an element which depends on props, say an array of names (which is defined as another component) then in react router's older versions, it was possible to pass props to the element using inline function but my question is that how we can do the same in V6?
If you're referring to just random props provided to the component at this level you can just do this:
<BrowerRouter>
<Routes>
<Route path="..." element={ <div> <MyComponent namesList={["John Doe"]} /></div> } />
<Route path="..." element={ <div> ... </div> } />
</Routes>
</BrowerRouter>
If you want to make use of the router props inside your components you can do so using the useLocation, useNavigate or useParams hooks within your component for this.
Another option is to create a HOC like this:
import {
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
Then use it on your component like this:
const MyComponent = (routerProps) => (...)
export default withRouter(MyComponent)
Is there a way to pass the location prop and own made prop to another component? I've figured out how to pass DIR_URL through a function like below but I also need to use location prop later in ConfirmAccount component to read pathname property and so on. (Of course in this way it gets true value).
import React, { Component, Fragment } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Main from './components/structure/Main';
import ConfirmAccount from './components/pages/ConfirmAccount';
import NoMatch from './components/pages/NoMatch';
class App extends Component {
render() {
const url = 'http://localhost:3006';
return (
<Fragment>
<Router>
<Switch>
<Route exact path="/" component={Main} />
<Route path="/confirm">
{/* How can I pass the location? */}
<Route path="/:url" component={() => <ConfirmAccount DIR_URL={url} location />} />
</Route>
<Route component={NoMatch} />
</Switch>
</Router>
</Fragment>
);
}
}
export default App;
React Router DOM automatically passes match location and history props.
You can use the route render prop to pass them manually if you wish:
<Route path="/:url" render={(routeProps) => <ConfirmAccount DIR_URL={url} {...routeProps} />} />
I suggest that you use useHistory hook from ReactRouterDom inside your child component. There you got all the location stuff that you need.
Or pass route properties to rendering component:
import React, { Component, Fragment } from 'react';
import { BrowserRouter as Router, Switch, Route, useHistory } from 'react-router-dom';
import Main from './components/structure/Main';
import ConfirmAccount from './components/pages/ConfirmAccount';
import NoMatch from './components/pages/NoMatch';
class App extends Component {
render() {
const url = 'http://localhost:3006';
return (
<Fragment>
<Router>
<Switch>
<Route exact path="/" component={Main} />
<Route path="/confirm">
{/* How can I pass the location? */}
<Route path="/:url" component={(routeProps) => <ConfirmAccount DIR_URL={url} {...routeProps} />} />
</Route>
<Route component={NoMatch} />
</Switch>
</Router>
</Fragment>
);
}
}
const ConfirmAccount = ({location}) => {
const history = useHistory()
}
export default App;
just import { useLocation } from 'react-router-dom' and use it like this:
const location = useLocation()
now you can access the location object.
read more about it here: https://reactrouter.com/web/api/Hooks/uselocation
or you can use withRouter HOC like this https://reactrouter.com/web/api/withRouter
I am new in ReactJs.
I need a route like localhost:3000/directory/category/region/brandName and for the same route, I need to render a component
Sample of URL be like
localhost:3000/directory/photography/france/testA
localhost:3000/directory/Catering/germany/testB
for both above URLs, a component called name.js should render
You can make use of react-router and then configure your Routes by making use of Route params
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const App () => {
return (
<Router>
<Switch>
<Route path="/directory/:profession/:country/:value" component={Name} />
<Route path="/" component={Dashboard}/>
</Switch>
)
}
Now post this you can access the params in name component and fetchData from api or have any other logic
const Name = () => {
const { profession, country, value} = useParams();
useEffect(() => {
// Any fetch logic based on params
}, [profession, country, value]);
return (
..
)
}
You can read more about react-router usage here and also refer the docs
As far as I understand from the question, you can handle this through using "Redirect" component. Let there be a "Navigation" component where the "Router" is defined as you did
Navigation.js
import Name from './name';
import From from './from';
<Router>
<Switch>
<Route path="/from">
<From />
</Route>
<Route path="/directory/:profession/:country/:value">
<Name />
</Route>
</Switch>
</Router>
and a "From" component where paths and redirections are defined. If "redirectionPath" is not null you can return "Redirect" component in render. Thus, you can redirect to and render the Name component.
From.js
import React, {Component} from 'react';
import {
Redirect
} from "react-router-dom";
class From extends Component {
state={
redirectionPath: "/directory/photography/france/testA" // or setState anywhere you need.
}
...
render(){
if(this.state.path){
return (<Redirect to={this.state.redirectionPath} />)
}
return (
<SomeComponent/>
);
}
}
This can be one of the solutions. Hope it works for you as well.