Reputation: 775
Scenario:
There is a homepage from where on searching user is redirected to a search page with a query param (eg q=abc). Now being on search page, user again tries to search for a different value so he is again redirected to same search page but with a different query param (eg q=xyz)
Problem:
When I am trying to perform a Redirect from Search page again to the same route with a different query param, I am getting an error "You tried to redirect to the same route you're currently on".
Expected Result:
User should be redirected to the same route again with a different query params so that on pressing back button he can go back to the previous query like it would normally be if it hadn't been a SPA. The result should be similar to the case where I had redirected the user from /search/abc to /search/xyz both using the same component.
Possible Solution:
On submitting a search query, I can check if it is the same route and based on that I can either redirect or update the component state some way. Problem with this solution is that user cannot go back to the previous query on clicking browser's back button. I want the page to be added in history.
Code Snippet:
Using below code for redirection in render function inside Search Component which is present on both homepage and search page
if (this.state.isReady) {
let queryString = "q=" + this.state.q;
return (
<Redirect push to={`/search/hotels?${queryString}`} />
);
}
I think this is a common problem with any site having a search feature so there should be an elegant way to handle such a situation but I am unable to think about it.
Upvotes: 24
Views: 35360
Reputation: 1387
I'm not a fan of other solutions that dip into the history api. I see react-router as providing an abstraction on top of regular browser links/history, so I'd rather change how I'm using that library.
We have a regular Link component:
<Link to='/products/new'/>
and this ^ doesn't need to change. Instead, we changed our Route from this
<Route path="/products/new" component={Whatever} />
to this:
<Route path="/products/new" component={Whatever} key={history.location.key} />
and that made it just work. I believe this works because history.location.key
is changing whenever the user clicks on a Link component, and that forces the Route to be recreated. So now the component is getting a fresh state like we want.
This is for react-router v4 (yes, it's old...)
Upvotes: 0
Reputation: 31
Here's my solution using React hooks. Made a new file for these components and import wherever I need it.
import { Route, Link, useLocation, Redirect } from 'react-router-dom';
export const LinkWithQuery = ({ children, to, ...props }) => {
const { search } = useLocation();
return (
<Link to={to + search} {...props}>
{children}
</Link>
);
};
export const RedirectWithQuery = ({ to, exact, from }) => {
return (
<Route
exact={exact}
path={from}
render={(props) => <Redirect to={`${to}${props.location.search}`} />}
/>
);
};
Upvotes: 2
Reputation: 1330
For react-router-dom
v5.1 the to
object can include the search
field
<Redirect to={{ pathname: "/search/hotels", search: `?${queryString}` }} />
If you manually concatenate those in pathname
it doesn't work as expected in my use case. Notice the ?
included in the search
param.
Also, this to
structure has a similar shape to the returned when using the RouterComponentProps
.
import { RouteComponentProps } from 'react-router-dom';
interface Props extends RouteComponentProps<{}> {}
export function GoToPrevious(props: Props) {
// previous page
let from = (props.history.location.state as any)?.from
// remember to check undefined's here
return <Redirect to={from}></>;
}
Upvotes: 0
Reputation: 537
The easiest solution I found was just using the location.search prop:
<Redirect from="/color-profile/quiz" to={`/quiz?${props.location.search}`} exact />
Upvotes: 1
Reputation: 618
Ebis answer did not work correctly for me.
When adding the query string directly to the pathname
, react router tried to match the path, resulting in not founding the route when using the Redirect
component.
A workaround was to add a /
before the query string like so:
<Redirect to={{ pathname: `/search/hotels/?${queryString}` }} />
However, this didn't seem right. Instead, I've added only the path to the pathname
, and the query string to the search
key like so:
<Redirect to={{ pathname: '/search/hotels', search: `?${queryString}` }} />
Upvotes: 3
Reputation: 460
Hey you could use the object notation instead of a string literal, and pass a location object containing the new pathname you would like to redirect to example
const Topic = ({ location }) => (
<Redirect to={{ ...location, pathname: '/topics?user=prolific' }} />
)
so using the spread operator, you retain previous properties of location, and then you can change the pathName to the one you want.
or
You could just format the query for the new route and prepend the route name, before passing it to the Redirect component. e.g.
const Topic = ({ location }) => {
const userQuery = 'user=prolific&title=The Long Night';
const newRoute = `topics?${userQuery}`
return <Redirect to={newRoute} />
}
Hope that helps
Upvotes: 2
Reputation: 775
Found A Solution:
Instead of using <Redirect />
from React Router, I used history api to push a new route.
this.props.history.push(`/search/hotels?${queryString}`);
I wrapped my SearchComponent inside withRouter which is a HOC provided by React-Router and then used the history api.
Code Snippet:
import { withRouter } from 'react-router-dom';
class SearchComponent {
// Component Code goes here
onSubmit(){
let queryString = "q=" + this.state.q;
this.props.history.push(`/search/hotels?${queryString}`);
}
}
export default withRouter(SearchComponent)
Upvotes: 19