Skip to content

Commit 428da54

Browse files
committed
[added] Support <Redirect to="relative/path">
1 parent 0f5b493 commit 428da54

File tree

2 files changed

+58
-7
lines changed

2 files changed

+58
-7
lines changed

modules/Redirect.js

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,22 @@ const Redirect = React.createClass({
2323
if (route.from)
2424
route.path = route.from
2525

26-
// TODO: Handle relative pathnames, see #1658
27-
invariant(
28-
route.to.charAt(0) === '/',
29-
'<Redirect to> must be an absolute path. This should be fixed in the future'
30-
)
31-
3226
route.onEnter = function (nextState, replaceState) {
3327
const { location, params } = nextState
34-
const pathname = route.to ? formatPattern(route.to, params) : location.pathname
28+
29+
let pathname
30+
if (route.to.charAt(0) === '/') {
31+
pathname = formatPattern(route.to, params)
32+
}
33+
else if (!route.to) {
34+
pathname = location.pathname
35+
}
36+
else {
37+
let routeIndex = nextState.routes.indexOf(route)
38+
let parentPattern = Redirect.getRoutePattern(nextState.routes, routeIndex - 1)
39+
let pattern = parentPattern.replace(/\/*$/, '/') + route.to
40+
pathname = formatPattern(pattern, params)
41+
}
3542

3643
replaceState(
3744
route.state || location.state,
@@ -41,6 +48,22 @@ const Redirect = React.createClass({
4148
}
4249

4350
return route
51+
},
52+
53+
getRoutePattern(routes, routeIndex) {
54+
let parentPattern = ''
55+
56+
for (let i = routeIndex; i >= 0; i--) {
57+
let route = routes[i]
58+
let pattern = route.path || ''
59+
parentPattern = pattern.replace(/\/*$/, '/') + parentPattern
60+
61+
if (pattern.indexOf('/') === 0) {
62+
break
63+
}
64+
}
65+
66+
return '/' + parentPattern
4467
}
4568

4669
},

modules/__tests__/Redirect-test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,32 @@ describe('A <Redirect>', function () {
2929
})
3030
})
3131

32+
it('works with relative paths', function (done) {
33+
React.render((
34+
<Router history={createHistory('/nested/route1')}>
35+
<Route path="nested">
36+
<Route path="route2" />
37+
<Redirect from="route1" to="route2" />
38+
</Route>
39+
</Router>
40+
), node, function () {
41+
expect(this.state.location.pathname).toEqual('/nested/route2')
42+
done()
43+
})
44+
})
45+
46+
it('works with relative paths with param', function (done) {
47+
React.render((
48+
<Router history={createHistory('/nested/1/route1')}>
49+
<Route path="nested/:id">
50+
<Route path="route2" />
51+
<Redirect from="route1" to="route2" />
52+
</Route>
53+
</Router>
54+
), node, function () {
55+
expect(this.state.location.pathname).toEqual('/nested/1/route2')
56+
done()
57+
})
58+
})
59+
3260
})

0 commit comments

Comments
 (0)