I am trying to run an onLoad event to get data from my db. I need to use a url parameter as a the prop to do this with but can't figure out how to access it.
I am using react-router v6, although in my package.json it is called react-router-dom.
Here is my setup
index.js
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/newrecipe" element={<RecipeForm />} />
<Route path="/recipe/:name" element={<RecipeDBTest />} /> //relevant line
</Routes>
</BrowserRouter>
Then in RecipeDBTest.jsx I need to grab the final parameter from my url string that looks like this:
http://localhost:3000/recipe/toast
So I would grab toast from URL string and pass to server with a fetch request on the RecipeDBTest.jsx page.
Just hoping for some advice/guidance here.
You can use useParams hook of react-router.
import {
useParams
} from "react-router-dom";
function Child() {
// We can use the `useParams` hook here to access
// the dynamic pieces of the URL.
let { name } = useParams();
return (
<div>
<h3>Name: {name}</h3>
</div>
);
}
let name = this.props.match.params.name
Related
We are looking to add custom logging to our react application, and would like to log each time a user changes routes. To handle this, we are creating a wrapper component , and this is what we currently have:
import React, { useEffect } from 'react';
import { Route } from 'react-router-dom';
function LoggerRoute(isExact, path, element) {
useEffect(() => {
// send route-change log event to our mongodb collection
}, []);
// And return Route
return (
isExact
? <Route exact path={path} element={element} />
: <Route exact path={path} element={element} />
);
}
export default LoggerRoute;
...and in our App.js file, we have changed the routes as such:
// remove this // <Route exact path='/tools/team-scatter' element={<TeamScatterApp />} />
<LoggerRoute isExact={true} path='/tools/team-scatter' element={<TeamScatterApp />} />
However, this throws the error Uncaught Error: [LoggerRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>.
Additionally, it feels off passing props to a route, if possible we would prefer
<LoggerRoute exact path='/tools/team-scatter' element={<TeamScatterApp />} />
as the ideal way to call our LoggerRoute. We like the idea of a wrapper component, this way we don’t have to add logging into every component that our app routes to. However, I’m not sure if this wrapper component approach is possible if can only accept a component. How can we modify our LoggerRoute component to work / be better?
In react-router-dom#6 only Route and React.Fragment are valid children of the Routes component. Create either a wrapper component or a layout route component to handle listening for route path changes. Since you presumably want to do this for more than one route at-a-time I suggest the layout route method, but you can create a component that handles either.
Example:
import { Outlet, useLocation } from 'react-router-dom';
const RouteListenerLayout = ({ children }) => {
const { pathname } = useLocation();
useEffect(() => {
// send route-change log event to our mongodb collection
}, [pathname]);
return children ?? <Outlet />;
};
The children prop is used in the cases where you want to wrap individual routed components (i.e. the element prop) or an entire component, (*i.e. App) that is rendering a set of Routes. The Outlet component is used in the case where you want to conditionally include a subset of routes within a Routes component (i.e. some nested Route components).
Wrap the routes you want to listen to route changes for.
Examples:
<Routes>
<Route element={<RouteListenerLayout />}>
<Route path="path1" element={<SomeComponent />} />
<Route path="someOtherPath" element={<SomeOtherComponent />} />
... wrapped routes components with listener
</Route>
... routes w/o listener
</Routes>
or
<Routes>
<Route
path="/"
element={(
<RouteListenerLayout>
<SomeComponent />
</RouteListenerLayout>
)}
/>
</Routes>
or
<RouteListenerLayout>
<App />
</RouteListenerLayout>
These all assume the router is rendered higher in the ReactTree than RouteListenerLayout so the useLocation hook works as expected.
In v6, <Route> is a lot more strict than it was in v5. Instead of building wrappers for , it may be used only inside other <Routes> or <Route> elements. If you try to wrap a <Route> in another component it will never render.
What you should be doing instead is adding a wrapper component and leveraging it in the element prop on the route.
function App() {
return (
<Routes>
<Route path="/public" element={<PublicPage />} />
<Route
path="/route"
element={
<AddLogging>
<YourPage/>
</AddLogging>
}
/>
</Routes>
);
}
Edit: here is an example wrapper component based on your needs:
function AddLogging({children}) {
useEffect(() => {
// send route-change log event to our mongodb collection
// can use useLocation hook to get route to log
}, []);
return children;
}
I want to use the react router to show a page according to the first part of the URL, because the last part of the URL is holding an ID. How can I read out the last part, now I'm using string.split("/").pop()
URL
http://localhost:3003/profile/313a2333
Router
<Routes>
<Route path="/profile" element={<Profile/>} />
</Routes>
Define your Route like the following:
<Route path="/profile/:user_id">
Then you can get 2nd parameter in Profile component.
import { useParams } from 'react-router-dom';
const params: any = useParams();
const user_id = params.user_id;
If you don't care about the second path segment and only want to match according to the first segment then use a "*" wildcard matcher.
<Routes>
<Route path="/profile/*" element={<Profile/>} />
</Routes>
If you do need to capture this second path segment value, then provide a param name for it.
<Routes>
<Route path="/profile/:id" element={<Profile/>} />
</Routes>
Use the useParams hook to access route path params in the routed components.
const { id } = useParams();
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)
I have a react app, and a component that is supposed to load a set of value of the url
<PersistGate persistor={rootStore.persistor}>
<Router history={history}>
<ErrorBoundary>
<Preloader history={history} /> <== this need to read the url
<PasswordChecker></PasswordChecker>
<RouteDispatcher></RouteDispatcher> <== this contain the list of routes
</ErrorBoundary>
</Router>
</PersistGate>
In my RouteDispatcher path I have setup the route like this :
<BrowserRouter>
<Switch>
<PrivateRoute path="/ws/:ws/pj/:pj/ds/:ds" component={HomeDatastore} />
<PrivateRoute path="/ws/:ws/pj/:pj" component={HomeProject} />
<PrivateRoute path="/ws/:ws" component={HomeWorkspace} />
</Switch>
</BrowserRouter>
how would I get the value of ws=:ws pj=:pj etc...
I was thinking of doing it with a regex, but I wonder if there is a better way. Preloader is outside the routeDispatcher, so I don't seem to find a good way to get the value.
React router provides params into the component. Check props.match.params. I see that you have a custom component PrivateRoute so first check props in PrivateRoute.
May be try using useParams() hook. It gives you a way to access the URL params
Reference: https://blog.logrocket.com/react-router-hooks-will-make-your-component-cleaner/
Sandbox: https://codesandbox.io/s/react-router-useparams-hooks-q8g37
This might help you get started with it
import { useParams } from "react-router-dom";
function ComponentName() {
let params = useParams();
return (
<div>
{params.ws}
{params.pj}
</div>
);
}
I'm trying to implement React Router with query params like so http://localhost:3000/login?Id=1, I was able to achieve it only for my login route that too if I put path as http://localhost:3000/ which then redirects , however, I want to implement across the application. It matches nomatch route if I implement on other routes. This is how my index.js looks like, Can someone guide me how can i go about implementing all routes path including query params ?.
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route
exact
path={`/`}
render={() => {
if (!store.getState().login.isAvailable) {
return <Redirect to={`/login?Id=${Id}`} />
} else {
return <Dashboard />
}
}}
/>
<Route exact path={`/login`} component={Login} />
<Route exact path={`/signup`} component={SignUp} />
{Routes.map((prop, key) => (
<Route path={prop.path} key={key} component={prop.component} />
))}
<Route component={NoMatch} />
</Switch>
</BrowserRouter>,
document.getElementById('root')
)
There are two ways about to accomplish what you want.
The most basic way would be on each "page" or root component of each route, handle the parsing of query params.
Any component that is the component of a Route component, will have the prop location passed to it. The query params are located in location.search and that will need to be parsed. If you are only worried about modern browsers, you can use URLSearchParams, or you can use a library like query-string, or of course, you can parse them yourself.
You can read more in the react-router docs.
The second way of doing this, really isn't that different, but you can have a HOC that wraps around each of your "pages" that handles the parsing of the query params, and passes them as a list or something to the "page" component in question.
Here's an example of the basic way using URLSearchParams:
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
// this is your "page" component, we are using the location prop
function ParamsPage({ location }) {
// you can use whatever you want to parse the params
let params = new URLSearchParams(location.search);
return (
<div>
<div>{params.get("name")}</div>
// this link goes to this same page, but passes a query param
Link that has params
</div>
);
}
// this would be equivalent to your index.js page
function ParamsExample() {
return (
<Router>
<Route component={ParamsPage} />
</Router>
);
}
export default ParamsExample;
EDIT: and to clarify, you don't need to do anything on your index.js page to make this work, the simple Routes you have should work fine.