In my application I change a query parameter often. The code to do this requires some boilerplate. The code I have currently looks like this:
const router = this.props.router;
const path = router.getCurrentPathname();
const params = router.getCurrentParams();
const query = router.getCurrentQuery();
query.q = this.props.query;
router.transitionTo(path, params, query);
It could work like angular's $location.search
Then the code above could look like:
router.query('q', this.props.query);
I think this could be a useful enhancement.
I find myself transitioning between a route with slightly different query params a lot as well (like filtering a list). Is this the idiomatic react router way? I would like it to have a little less boilerplate if possible.
0.13.x
<Link to="/somewhere" query={Object.assign({}, this.props.query, newStuff)}/>
1.0
<Link to="/somewhere" query={Object.assign({}, this.props.location.query, newStuff)}/>
Seems pretty good to me, what do you think? If its no good, we can reopen, we get this question quite a bit.
My query parameter changes based on a submission of a search box. This means that I am transitioning programmatically in a onSubmit handler. I don't see how I can use the link component there.
It would make sense if the transitionTo
methods would work the same like the link component. Maybe something like:
transitionTo({q: this.props.query}) // only sets query param q
or
transitionTo(null, null, {q: this.props.query}) // sets all query params
A null value would default to the current value. To reset the value you would do something like this:
transitionTo('',{},{});
But honestly I like the solution based on $location.search
I suggested in the OP best:
router.query('q', this.props.query); // sets only the query param q
router.query({q: this.props.query}); // overwrites all query params
router.query('q'); // would return the current value of query param 'q'
Therefore I suggest reopening this issue.
My problem with the current Object Assign solution is that if my query parameters is allowed to be a list like "?year=2015&year=2016", the current solution will only take it as and update from "?year=2015" to "?year=2016".
Then I try to do some logic in the render() to calculate the new queryObject as I need to change a string value to an array, calculated obj is wrong as the render() could be trigger other than a click action.
To allow adding logic to change query, I am not aware of any method for now to update it correctly.
I would think a append option for query is needed and the href could be all "?year=2016", the current method will update all the link related to query to be "?xxxxxxxxxx&newquery" which its not what is should be.
Is there any good method for this?
Like @0xR I want to add query params but not have to pass in the current pathname
- I have a series of filters and I want to add a query param for every filter selected to enable bookmarking.
To enable something like...
onFilterChange(filterName, val) {
addQuery({ filterName: val });
}
I'd like to be able to do this without passing in the current pathname
every time. Any help appreciated :)
Currently I am totally lost, I would like to change the query params somehow, from a handler, like @robhadfield and I am even not able to use the methods in OP above..
Google searches brings me to context
based solutions, but it seems to be deprecated.. I guess there must be a simple way, but I DONT know it, and most of the posts are just and obsolete..
Any update on this?
What I found was this:
this.context.history.push({
...this.props.location,
query: {someParam: "value"}
});
So you can create programmatically your query with the old params.. and then assign it..
var query = { ...this.props.location.query, newParam: "blub" }
this.context.history.push({
...this.props.location,
query
});
dont forget to add history to the contextTypes ;)
@dropfen Where in your code did you use this? The place where you trigger the route transition I guess?
I am using it in the components methods, which get called on events like changing a dropdown filter..
Ok, thank you! :)
you are welcome :)
Yes, and see the v3 alpha changelog, which makes <Link to>
also take a function, so you can do to={location => ({ ...location, query: nextQuery })}
I am trying to build a search function into my app and am totally lost. Is there a universal solution yet??
My <Search />
component is very complex.
<List/>
My usage of react-router so far has been reduced to browserHistory.push('/')
@FinnFrotscher maybe this helps..
this.context.history.push({
...this.props.location,
query: Object.assign({}, this.props.location.query, {foo:"bar"})
});
you have to push a new react-router location into the history, you can specify the query params with the query key. The above example will assign foo=bar to the current query. If you would like to remove a param you would need to set it to undefined.. thats it.
I have a history
obj in my props
but not in my context
. Should I use that?
My context is mostly empty.
I only just set up SearchInterface.contextTypes = {
router: routerShape.isRequired
}
and import {browserHistory, routerShape} from 'react-router'
@FinnFrotscher yes, for me it worked with history
required by contextTypes
I've end up with these:
import { browserHistory } from 'react-router';
/**
* @param {Object} query
*/
export const addQuery = (query) => {
const location = Object.assign({}, browserHistory.getCurrentLocation());
Object.assign(location.query, query);
browserHistory.push(location);
};
/**
* @param {...String} queryNames
*/
export const removeQuery = (...queryNames) => {
const location = Object.assign({}, browserHistory.getCurrentLocation());
queryNames.forEach(q => delete location.query[q]);
browserHistory.push(location);
};
And example usage:
import { withRouter } from 'react-router';
import { addQuery, removeQuery } from '../../utils/utils-router';
function SomeComponent({ location }) {
return <div style={{ backgroundColor: location.query.paintRed ? '#f00' : '#fff' }}>
<button onClick={ () => addQuery({ paintRed: 1 })}>Paint red</button>
<button onClick={ () => removeQuery('paintRed')}>Paint white</button>
</div>;
}
export default withRouter(SomeComponent);
@DimitryDushkin I am not sure what you pass in as the router param. Could you help give some context?
@jonearley I've updated comment https://github.com/ReactTraining/react-router/issues/1100#issuecomment-272800685 with example
Thank you, just adding this here in case anyone has the same issue with that code snippet: if it's scrolling to top on update, may be due to having react-router-scroll installed (I am new to react and used yeoman generator to create my base project). In my case, don't need that for this project and so uninstalled it.
In v4 I have a simple solution:
this.props.history.push('?tab=summary');
I just found a solution to this problem that doesn't require using browserHistory
and seemed somewhat elegant (in ES6):
// To set a parameter:
<Link to={{
pathname: router.location.pathname,
query: {
...(router.location.query),
myProp: 'foo',
}
}} />
// To unset:
const query = router.location.query;
delete query['myProp'];
/* ... */
<Link to={{
pathname: router.location.pathname,
query,
}} />
// Also, to keep track of whether Link is active
// (query params are not tracked by the Link component):
<Link
/* ... */
className={'foo' === query['myProp'] ? 'active' : ''}
/>
This example is modified from my own code so please tell me if it has errors or if it's to terse.
With react-router-4, if you need to append a query param programmatically you can do this:
const query = new URLSearchParams(history.location.search)
query.set('foo', 'bar')
history.replace({...history.location, search: query.toString()})
Managed to add query params by simply using "search" property:
<Link to={{pathname: "/some/path", search: props.location.search}}>Title</Link>
Most helpful comment
I've end up with these:
And example usage: