-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Resolve relative paths #4122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve relative paths #4122
Conversation
@@ -8,6 +8,7 @@ describe('HashRouter', () => { | |||
const div = document.createElement('div') | |||
|
|||
afterEach(() => { | |||
window.location.hash = '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to reset this because the 'hashType noslash'
tests are run after the 'hashType hashbang'
tests, at which point the hash is #!/
, which breaks the 'adds a hash link'
test because it uses a relative URL and would become #!/foo
instead of #foo
.
@@ -24,11 +24,58 @@ export const createRouterLocation = (input, parseQueryString, stringifyQuery) => | |||
} | |||
} | |||
|
|||
export const createRouterPath = (input, stringifyQuery) => { | |||
return typeof input === 'string' ? input : createPath({ | |||
export const createRouterPath = (input, stringifyQuery, base) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not make this 3rd arg optional, with a default to ''
? Less code changes elsewhere that way.
2cd33d7
to
22838ed
Compare
I think that this is at a decent place right now. The main interaction is done through a
This doesn't try to automatically resolve locations when a user is manually navigating. In order to do that, the import { resolveLocation } from 'react-router'
class MyComponent extends React.Component {
back(loc) {
const { match, router } = this.context
const base = match && match.parent && match.parent.pathname
router.transitionTo(resolveLocation('..', base))
}
} (I'm not actually exporting it in the lastest PR, but that's a simple fix) |
a8481f2
to
16f3b88
Compare
16f3b88
to
ca689af
Compare
Rebased for the latest version. The new match context is a bit annoying to work with, but everything checks out. |
The resolving of relative paths is done using a modified version of RFC 1808. This is done for two reasons: 1) React Router only considers pathnames, so protocol relative paths can be disregarded. 2) RFC 1808 resolves paths on the last segment with a trailing forward slash (foo/bar resolves from foo and bar is discarded), but in React Router the last segment is preserved unless it is an empty string (foo/bar and foo/bar/ resolve from bar). <Link> and <Redirect> components have their "to" prop automatically resolved using their parent match's pathname. If there is no parent match's pathname, then they are resolving using the root path (an empty string). For imperative navigation, the resolveLocation method is exported. The user is able to generate an absolute location by giving it a location (a pathname string or a descriptor object) and the base pathname to resolve off of.
ca689af
to
32cfdf1
Compare
When's this coming in? |
I'm afraid this PR is a bit oudated, but I'd like to explain how we're handling relative Relative <Route path="/users/:id" render={({ match }) => (
<div>
<Route path={`${match.path}/profile`} component={UserProfile}/>
</div>
)}/> Relative <Route path="/users/:id" render={({ match }) => (
<div>
<Link to={`${match.url}/profile`}>user profile</Link>
</div>
)}/> Thanks for taking the time to contribute :) Please take another look at v4. We're pushing for a beta this week. |
@mjackson I think one main use-case for relative paths would be to use |
@sgoll Yes, you should be able to use relative You will also probably be interested in the discussion going on in #4332 (comment) |
I know that @ryanflorence has mentioned some work on relative URLs in other threads, but I thought that I'd make a pull request with a possible working option based on RFC 1808.
I left in comments so that hopefully it should be understandable, but you might also need to reference the RFC 1808 steps. It passes the tests described by 1808, albeit with one modification:
In 1808, anything after the final forward slash in the base url is removed before resolving URLs. However, in React Router, the content after the final forward slash is the base for its children, so it should not be stripped. The tests have been updated to reflect this.
Note: I'm exporting the
makeRootRelative
function because it was convenient while I was writing this, but the tests for it should just be folded into thecreateRouterPath
tests.Currently the only tests are the examples from the RFC, so those will probably need to be expanded to ensure correctness, but hopefully this can be a good starting point for addressing the issue (mostly because I dislike writing
to={`${pathname}/bar`}
).