I am using React Router v4 for routing in my application. The only issue I have is the query params are ignored while navigation from one route to another. Is there a way to just replace the path and preserve the query params.
Below is my code:
<Switch>
<Route exact path="/" component={() => <Redirect to="/Route1" />}/>
<Route exact path='/Route1' component={Route1Comp} />
<Route path='/Route1/:channel/:id?'
render={(routeProps) => (
<AppMain {...routeProps} />
)}
/>
<Route exact path='/Route2' component={Route2Comp} />
</Switch>
I need the app to have a query param ?isDev=true and want to retain across. Currently if I am on localhost:3000/Route1Comp?isDev=true and navigate to Route2Comp using Link then the entire path is replaced along with query params.
You can extend the Link component from react-router to include the search params by default like
const ExtendedLink = ({ to, children, location}) => {
return <Link to={{
pathname: to,
search: location.search
}}>{children}</Link>
}
export default withRouter(ExtendedLink)
and then use it instead of Link
<ExtendedLink to='/Route1'>Route 1</ExtendedLink>
Related
I have a route defined as following:
<Route path={`${match.path}/:id`} component={SheetRoutes} />
And SheetRoutes:
const SheetRoutes = ({ match }: RouteComponentProps): JSX.Element => (
<Switch>
<Sheet>
<Route
exact
path={`${match.path}/`}
render={() => <Redirect to={`${match.path}/general`} />}
/>
<Route path={`${match.path}/general`} component={GeneralRoutes} />
...
</Sheet>
<Redirect strict to='/404' push />
</Switch>
);
I want when the user types /5 in the url to redirect him to /5/general, in this case it works fine and the view is updated accordingly.
The problem I'm having is that the url in the browser drops the id value and it looks like this: /:id/general instead of /5/general.
How can I solve this?
For Redirect component in your SheetRoutes, it should be match.url (which is the real path value) instead of match.path.
I have been assigned a task where I must put a route with the following url: /items?search= to load SearchBarScreen component.
I have this code and I am using react-router-dom package:
export const AppRouter = () => {
return (
<Router>
<Switch>
<Route exact path="/items?search=" component={SearchBarScreen} />
<Route exact path="/product/:id" component={ProductDetailScreen} />
<Route path="/" component={HomeScreen} />
<Route component={NotFoundScreen} />
</Switch>
</Router>
);
I can't load my SearchBarScreen component with the url:
http://localhost:3000/items?search=XDDD
the route HomeScreen (/) is loaded in this case :(
what am I doing wrong?
You should feed the URI without the query string to the Route component. So if you want to render your SearchBarScreen at this URL http://localhost:3000/items?search=, you should do this:
<Route exact path="/items" component={SearchBarScreen} />
And then access the query string inside SearchBarScreen like so:
const SearchBarScreen = ({ match, location }) => {
console.log(location.search);
return <div>Search results</div>;
};
Another way is to drop the exact prop.
My recommended solution is the former. Here is a Sandbox: https://codesandbox.io/s/elated-http-lkqfj?file=/src/App.js
The exact param is used when you have multiple paths that have similar names:
for exmplae in your code when you go to //localhost:3000/items?search=XDDD the router will go through all of our defined routes and return the FIRST match it finds.And this is the first thing it finds //localhost:3000/ And executes the HomeScreen component.
The exact param disables the partial matching for a route and makes sure that it only returns the route if the path is an EXACT match to the current url.
So in this case,you should add exact to / route:
<Router>
<Switch>
<Route path="/items?search=" component={SearchBarScreen} />
<Route path="/product/:id" component={ProductDetailScreen} />
<Route exact path="/" component={HomeScreen} />
<Route component={NotFoundScreen} />
</Switch>
</Router>
You can do something like this
You can use this custom hook
useLocation hook is imported from react-router-dom
useQuery() {
return new URLSearchParams(useLocation().search);
}
Then in component
const query = useQuery();
Docs Query param example
I required to redirect from parent path to child path as a default. but the route is getting updates. but the component is not rendering.
here is my route details:
Lazy part:
const UK = React.lazy(() => import("./components/page-projects/project-uk/project-uk.component"));
const FR = React.lazy(() => import("./components/page-projects/project-france/project-france.component"));
const LT = React.lazy(() => import("./components/page-projects/project-lithuania/project-lithuania.component"));
Route path:
<Redirect from="/projects" to="/projects/united-kingdom">
<Route path="/projects/united-kingdom" component={UK}></Route>
<Route path="/projects/france" component={FR}></Route>
<Route path="/projects/lithuania" component={LT}></Route>
</Redirect>
what is wrong here? any one help me? my version of react is 17x
The other routes don't have to be children of Redirect.
You should be doing something like this
<Switch>
<Redirect from="/projects" to="/projects/united-kingdom" />
<Route path="/projects/united-kingdom" component={UK} />
<Route path="/projects/france" component={FR} />
<Route path="/projects/lithuania" component={LT} />
</Switch>
Reference https://reactrouter.com/web/api/Redirect
The <Switch /> component will only render the first route that matches the path. Once it finds the first route that matches the path, it will not look for any other matches. Not only that, it allows for nested routes to work properly and since the Redirect is a route you should wrap under the Switch component
<Switch>
<Redirect from="/projects" to="/projects/united-kingdom" />
<Route path="/projects/united-kingdom" component={UK} />
<Route path="/projects/france" component={FR} />
<Route path="/projects/lithuania" component={LT} />
</Switch>
I have many routes
<Route exact path="/" component={Test} />
<Route exact path="/1" component={Test1} />
<Route exact path="/2" component={Test2} />
In every component i use useLocation to get the data from route. It exists a possibility to pass in Route a parameter and to access that parameter with useLocation, in every component?
Here is the example:
<Route exact path="/" parameter='this is route nr 1' component={Test} />
<Route exact path="2/" parameter='this is route nr 2' component={Test2} />
Which is the solution to do what i want to achieve?
For query params you don't need to do anything extra in <Route />. You just need to get those query params in component and parse it
To access param1 from url
/?param1=hello
import { useLocation } from 'react-router-dom';
const Test = () => {
const queryParams = new URLSearchParams(useLocation().search);
return (
<div>Test {queryParams.get('param1')}</div>
);
}
And if you want path params like
/1 // 1 from this route
In routes and you don't need to create multiple routes just to get 1,2 etc
<Route exact path="/:id" component={Test} />
In component
import { useParams } from 'react-router-dom';
const Test = () => {
let { id } = useParams();
return (
<div>Test ID: {id}</div>
);
}
It seems from your question that you search for a way to pass data to routes only at the router declaration. therefore you can use regular props instead of location data extract -
<Route exact path="/" render={()=><Test parameter={'this is route nr 1'} />} />
You can either pass props to the component directly using render:
<Route
exact
path="/"
render={props => <MyComponent {...props} foo="hello world" bar={false} /> }
/>
or you can use query params:
<Route
exact
path={`/user?id=${user_id}`}
component={MyComponent}
/>
and then in MyComponent you can access props.match.params.id
React-router docs are a great start
I ask this question just want to make sure that I understand the dynamic nested routes in React Router v4 correctly. I want to build a hacker news client similar to this one. But I am bogged down by setting up the dynamic routes.
In React Router v4, if I follow other tutorials on the web using the match object I will have something like this (A super simple one):
const ChildComponent = ({rows, match}) => (
<div>
<ol>
rows.map((row, i) => {
return (
<li key={row.id}>
<a href={row.url}>row.title</a> // topic title
<Link to=`${match.url}/${row.by}`>row.by</Link> // topic author
</li>
)
}
</ol>
<Route path=`${match.url}/:userId` render={(props) => <UserProfile fetchUserData={fetchUserData} {...props} />} />
</div>
)};
And when we render the parent component, we usually use something like this for routing:
<Switch>
<Route path="/" render={Home} />
<Route path="/topics" render={(props) => <ChildComponent rows={rows} {...props} /> } />
<Route path="*" render={() => <div>Not Found</div>} />
</Switch>
But this is not ideal for this case, as when I click to view the author's info I need to display a url like this: "http://mysite/user/userid" instead of the current one which is "http://mysite/news/userid".
However, if I change ${match.url}/${row.by} to /user/${row.by} and change ${match.url}/:userId to /user/:userId the route is not recognized in the app. The route begins with /user/ is simply skipped, it will go straight to the app's NotFound route (if there is one), which is in the parent component. Why will the links in child component try to match the routes in the parent if I don't use ${match.url} in the route?
I have added a demo for you to easier to understand this problem.
Because when you'll click the /user/:userId: link the app will parse the Router's Switch to see if something matches. If it doesn't it fallback to *.
In your case, you did not specify anything in the Switch to handle /user .
You'll need to move your userId Route declaration to the Switch as they won't share the same first route (/user !== /topics).
<Switch>
<Route path="/" render={Home} />
<Route path="/topics" render={(props) => <ChildComponent rows={rows} {...props} /> } />
<Route path="/user/:userId" render={(props) => <UserProfile fetchUserData={fetchUserData} {...props} />} />
<Route render={() => <div>Not Found</div>} />
</Switch>