5

In React Router 4 I can define

<Route path="/calendar/:view/:year?/:month?/:day?" component={Calendar} />

to pass props from a URL to my Calendar component.

Inside the Calendar component, I want to programmatically set the URL params. The docs show how to do this using history.push(), but this requires you to format the URL yourself like history.push(``${view}/${year}/${month}/${day}``). But I want to update the URL without being coupled to the route structure, ideally something like history.push({ view: 'month', year: '2018' }).

Is this possible? It seems odd to me that React Router helps split up the URL into params, but doesn't provide a nice mechanism to set those params?

Cœur
  • 37,241
  • 25
  • 195
  • 267
dhulme
  • 159
  • 1
  • 2
  • 10
  • Directly with react router **No** you can [check this way](https://stackoverflow.com/questions/40161516/how-do-you-programmatically-update-query-params-in-react-router/40161954) but if you find yourself writing this a lot you can always write an Utils function to do the job. – Ryad Boubaker Jun 05 '18 at 15:56

4 Answers4

8

I do that by using match.path and generatePath. Here is an example:

this.props.history.push({
    pathname: generatePath(this.props.match.path, {orderId: "latest", orderItemId: "latest"})
});

You can read about it here https://reacttraining.com/react-router/core/api/generatePath and here https://reacttraining.com/react-router/core/api/match.

Thats the cleanest solution I found so far for preventing the route component from knowing to much about where it will be allocated later in the path structure. Maybe it fits your (or someone else's) need.

Mario Eis
  • 2,724
  • 31
  • 32
  • I can confirm this working. Keep in mind that `generatePath` will encode special characters like `/`, so you might want to use `decodeURIComponent` if you, like me, do a catch-all of all path params that are passed. – itachi Nov 28 '19 at 14:15
1

I would like to suggest that instead of history.push() as answered, you would use history.replace().

with replace you would not affect the history in case the user would want to navigate backward in the browser.

this.props.history.replace({
    pathname: generatePath(this.props.match.path, {orderId: "latest", orderItemId: "latest"})
});
Liran Brimer
  • 3,418
  • 1
  • 28
  • 23
0

I managed to implement this using the path-to-regexp package that React Router uses:

this.props.history.push(pathToRegexp.compile(this.props.match.path)({ view: 'month', year: '2018' ));
dhulme
  • 159
  • 1
  • 2
  • 10
-1

I'm not sure if what you want is achievable, because if you pass the params to the react-router-dom, the params goes to the URL, but if you decouple the params with the URL structure, how will react-router know how to change the URL? The same URL may match multiple routes, with multiple params structures (and nested routes).

Murilo Cruz
  • 2,387
  • 1
  • 17
  • 19
  • I meant that when the URL params come in as props into a component, they are decoupled from the URL structure as they are just an object. But when you update the URL, you can't pass in an object, you have to form the URL manually. – dhulme Jun 06 '18 at 08:25
  • This is not an answer. – tim-phillips Jul 29 '21 at 17:17