Desired behavior:
makePath
I think this behavior is pretty standard.
Today (as of v0.12.9) makePath
appends a trailing slash if a trailing slash is optionally allowed.
_Food for thought (tangential): It would be nice to support optional trailing slashes automatically without the need to add a /?
to all routes._
For me, the desired behavior would be
So I don't think changing the default behavior is the ideal solution. But it would be nice to have some more control over this.
+1
+1
+1
This is really an important issue. However, since the issue hasn’t been resolved, what is the workaround?
+1
+1
Yep, very annoying issue. Path must be handled with and without trailing slash by default as it is not classic REST router.
@ryanflorence @mjackson will this be addressed/changed in #1158? Does it make sense to implement it on the current code base, or should I rather start based on the code in #1158 ?
@Dignifiedquire This is already fixed in #1158
@mjackson how to solve this issue now?
its now optional in 1.0
workaround for this in 0.13.2
?
@kevzettler add /?
to the url
workaround for this in 0.13.2 ?
+1
/?
is not work in 1.0.0-beta3
?
It is not working in Link component. Class "active" is not added in case of trailing slash.
In the method Router#isActive are compared wrong strings:
to === state.path
which in my case of using /?
in route's path looks like this:
"/about" === "/about/"
Hi guys! Can't you just redirect every path with trailing slash to the path without it on server (using express
for example)?
It completely solved this issue for us.
@th0r yes I ended up with unification of all routes
(On 1.0.0-rc3) This is strange, but when using IndexRedirect
, having a trailing slash on the root path caused a problem for me.
If I do this (a slash after admin
):
<Route path='/admin/' component={App}>
<IndexRedirect to='posts' />
Then if I open a new window and go to localhost:.../admin/
it gets redirected to /admin/posts
correctly, BUT if I open a new window and go to localhost:.../admin
(without a slash at the end) it gives me an error:
Warning: Location "/admin" did not match any routes
To fix this, I had to remove the trailing slash from the root component:
<Route path='/admin' component={App}>
<IndexRedirect to='posts' />
I wanted to write a failing test but couldn't figure out how:
https://github.com/rackt/react-router/blob/c025177a10785f96f7683d4f033f6acdd46c1f2e/modules/__tests__/IndexRedirect-test.js#L20-L31
If someone could help me write a failing test, I'd create a new issue.
Just don't specify the trailing slash on path
if you want to match the slash-less route - easy enough.
For anyone wondering about how to do this in express:
// remove trailing slashes
app.use(function(req, res, next) {
if (req.path.length > 1 && /\/$/.test(req.path)) {
var query = req.url.slice(req.path.length)
res.redirect(301, req.path.slice(0, -1) + query)
} else {
next()
}
})
any update on this feature?
I found a solution that worked for me
"I added <base href="/" />
into the <head>
of my index.html and it worked (:"
Source:
http://stackoverflow.com/questions/28253162/react-router-dynamic-segments-crash-when-accessed
@Frikki: Old, I know, but I saw this somewhere. This will force all routes to end in a slash.
<Redirect from="/*" to="/*/" />
You need to import Redirect
from 'react-router'.
I'd love what @cmmartti worked, but it is causing an infinite loop for unknown paths as far as I understand.
I'm using react-router v2 and was able to force trailing slashes using onEnter
and onChange
hooks. All of my URLs are "directory" style, so I always add a trailing slash. If you need more sophisticated logic, this approach gives you the full power of JS to do so.
The technique relies on the fact that you can wrap all existing <Route>
s with a path
-less <Route>
without affecting your application. By adding hooks to the new top-level route, it catches all changes with no ill-effects.
My <Router>
:
<Router history={browserHistory}>
{/* ↓ This route hooks up the magic, all else can be replaced with your own routes */}
<Route onEnter={forceTrailingSlash} onChange={forceTrailingSlashOnChange}>
<Route path="/" component={MainLayout}>
<IndexRoute component={Dashboard} />
...other routes
</Route>
</Route>
</Router>
forceTrailingSlash
checks if the new path has a trailing slash and if not uses replace()
to add a trailing slash while preserving all other route data.
function forceTrailingSlash(nextState, replace) {
const path = nextState.location.pathname;
if (path.slice(-1) !== '/') {
replace({
...nextState.location,
pathname: path + '/'
});
}
}
forceTrailingSlashOnChange
simply delegates to forceTrailingSlash
, which is necessary because the onChange
hook has an extra argument we don't need.
function forceTrailingSlashOnChange(prevState, nextState, replace) {
forceTrailingSlash(nextState, replace);
}
Is there a solution for optional trailing slashes for v4?
(sorry for notification spam - deleted the first comment by accident)
Simple
```html
@pugnascotia From my understanding of the v4 design, the approach I described would still apply with light refactoring:
<Route>
to track changes, you'd just use a custom componentonEnter
and onChange
hooks with standard component lifecycle methods componentWillMount
and componentWillReceiveProps
.componentWillMount
is called on the server as well, and should work for universal apps. I'm not 100% sure these are the best lifecycle methods to replace RR's hooks, but I'm sure a future migration guide will make that clear.
@cristianele That's not a DRY solution for multiple routes. Also, isn't it good practice to support only a single URL for a given page of content? You're making a trailing slash optional for users, but also allowing two equivalent URLs for each route with that treatment.
For those of who are interested in forcing a trailing slash on specific routes:
<Route path="/:id(\d+)" exact strict render={props => <Redirect to={`${props.location.pathname}/`}/>}/>
This is nice if a user goes directly to /123
but your links are like <Link to={item}/>
to go to /123/item
Following up on @lewisdiamond's solution (using 4.1.x specifically), I believe enforcing trailing slashes for all routes can be achieved by making the following the first route in your router:
<Route path="/:url*" exact strict render={props => <Redirect to={`${props.location.pathname}/`}/>}/>
/:url*
and strict
match any number of /urlfragments
but this combination does not match the root url or any paths with a trailing slash. The render method issues a redirect that appends a / to the current path as in @lewisdiamond's post.
Sample root component:
render() {
return <Provider store={this.props.store}>
<Router history={this.props.history}>
<Switch>
<Route exact strict path="/:url*" render={props => <Redirect to={`${props.location.pathname}/`}/>} />
<Route exact path="/login" component={Login} />
<Route exact path="/logout" component={Logout} />
<Route path="/" component={MarketingSection} />
<Route path="/Subsection" component={SomeSubsectionComponent} />
<Route component={FourOhFour} />
</Switch>
</Router>
</Provider>
}
This change shouldn't require modifying routes anywhere else in an app as long as no routes strictly required no trailing slash (those would now be broken). I was able to drop this redirect into an existing app that was both defined as in the example above and exclusively used slashless internal links. Everything just worked with one exception: At one route in particular, there was some bad url join logic that assumed there'd be no trailing slash in the path and it only worked correctly in that case (meaning that the accessing that route with a trailing slash was broken before my change anyway). Be on the lookout for fun stuff like url.resolve(currentPath + '/', someID)
.
Note that non-matching routes of the form /some/bad/route
are redirected to /some/bad/route/
before displaying the FourOhFour
component in the example above. If one were to enforce trailing slashes at a web server level, this is very similar to the behavior you'd see there (web server redirects /some/bad/route
to /some/bad/route/
and then passes the request off to your application code which then responds with a 404).
Most helpful comment
I'm using react-router v2 and was able to force trailing slashes using
onEnter
andonChange
hooks. All of my URLs are "directory" style, so I always add a trailing slash. If you need more sophisticated logic, this approach gives you the full power of JS to do so.The technique relies on the fact that you can wrap all existing
<Route>
s with apath
-less<Route>
without affecting your application. By adding hooks to the new top-level route, it catches all changes with no ill-effects.My
<Router>
:forceTrailingSlash
checks if the new path has a trailing slash and if not usesreplace()
to add a trailing slash while preserving all other route data.forceTrailingSlashOnChange
simply delegates toforceTrailingSlash
, which is necessary because theonChange
hook has an extra argument we don't need.