mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-29 18:27:56 +02:00
fix(v2): normalize location for route matching (#2393)
* fix(v2): normalize location path for route matching * fix(v2): Memoize normalized pathnames * fix(v2): fix wrong reference to this.state instead of normalized location * Update normalizeLocation.js Co-authored-by: Yangshun Tay <tay.yang.shun@gmail.com>
This commit is contained in:
parent
c05cb75cbc
commit
a0570e48ac
3 changed files with 114 additions and 6 deletions
|
@ -11,6 +11,7 @@ import nprogress from 'nprogress';
|
||||||
|
|
||||||
import clientLifecyclesDispatcher from './client-lifecycles-dispatcher';
|
import clientLifecyclesDispatcher from './client-lifecycles-dispatcher';
|
||||||
import preload from './preload';
|
import preload from './preload';
|
||||||
|
import normalizeLocation from './normalizeLocation';
|
||||||
|
|
||||||
import 'nprogress/nprogress.css';
|
import 'nprogress/nprogress.css';
|
||||||
|
|
||||||
|
@ -37,19 +38,20 @@ class PendingNavigation extends React.Component {
|
||||||
// If `routeDidChange` is true, means the router is trying to navigate to a new
|
// If `routeDidChange` is true, means the router is trying to navigate to a new
|
||||||
// route. We will preload the new route.
|
// route. We will preload the new route.
|
||||||
if (routeDidChange) {
|
if (routeDidChange) {
|
||||||
|
const nextLocation = normalizeLocation(nextProps.location);
|
||||||
this.startProgressBar(delay);
|
this.startProgressBar(delay);
|
||||||
// Save the location first.
|
// Save the location first.
|
||||||
this.previousLocation = this.props.location;
|
this.previousLocation = normalizeLocation(this.props.location);
|
||||||
this.setState({
|
this.setState({
|
||||||
nextRouteHasLoaded: false,
|
nextRouteHasLoaded: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load data while the old screen remains.
|
// Load data while the old screen remains.
|
||||||
preload(routes, nextProps.location.pathname)
|
preload(routes, nextLocation.pathname)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
clientLifecyclesDispatcher.onRouteUpdate({
|
clientLifecyclesDispatcher.onRouteUpdate({
|
||||||
previousLocation: this.previousLocation,
|
previousLocation: this.previousLocation,
|
||||||
location: nextProps.location,
|
location: nextLocation,
|
||||||
});
|
});
|
||||||
// Route has loaded, we can reset previousLocation.
|
// Route has loaded, we can reset previousLocation.
|
||||||
this.previousLocation = null;
|
this.previousLocation = null;
|
||||||
|
@ -59,7 +61,7 @@ class PendingNavigation extends React.Component {
|
||||||
},
|
},
|
||||||
this.stopProgressBar,
|
this.stopProgressBar,
|
||||||
);
|
);
|
||||||
const {hash} = nextProps.location;
|
const {hash} = nextLocation;
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,7 +96,7 @@ class PendingNavigation extends React.Component {
|
||||||
this.clearProgressBarTimeout();
|
this.clearProgressBarTimeout();
|
||||||
this.progressBarTimeout = setTimeout(() => {
|
this.progressBarTimeout = setTimeout(() => {
|
||||||
clientLifecyclesDispatcher.onRouteUpdateDelayed({
|
clientLifecyclesDispatcher.onRouteUpdateDelayed({
|
||||||
location: this.props.location,
|
location: normalizeLocation(this.props.location),
|
||||||
});
|
});
|
||||||
nprogress.start();
|
nprogress.start();
|
||||||
}, delay);
|
}, delay);
|
||||||
|
@ -107,7 +109,9 @@ class PendingNavigation extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {children, location} = this.props;
|
const {children, location} = this.props;
|
||||||
return <Route location={location} render={() => children} />;
|
return (
|
||||||
|
<Route location={normalizeLocation(location)} render={() => children} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import normalizeLocation from '../normalizeLocation';
|
||||||
|
|
||||||
|
describe('normalizeLocation', () => {
|
||||||
|
test('rewrite locations with index.html', () => {
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/docs/introduction/index.html',
|
||||||
|
search: '?search=foo',
|
||||||
|
hash: '#features',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/docs/introduction',
|
||||||
|
search: '?search=foo',
|
||||||
|
hash: '#features',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/index.html',
|
||||||
|
search: '',
|
||||||
|
hash: '#features',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/',
|
||||||
|
search: '',
|
||||||
|
hash: '#features',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('untouched pathnames', () => {
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/docs/introduction',
|
||||||
|
search: '',
|
||||||
|
hash: '#features',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/docs/introduction',
|
||||||
|
search: '',
|
||||||
|
hash: '#features',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/docs/introduction/foo.html',
|
||||||
|
search: '',
|
||||||
|
hash: '#bar',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/docs/introduction/foo.html',
|
||||||
|
search: '',
|
||||||
|
hash: '#bar',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
34
packages/docusaurus/src/client/normalizeLocation.js
Normal file
34
packages/docusaurus/src/client/normalizeLocation.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Memoize previously normalized pathnames.
|
||||||
|
const pathnames = {};
|
||||||
|
|
||||||
|
function normalizeLocation(location) {
|
||||||
|
if (pathnames[location.pathname]) {
|
||||||
|
return {
|
||||||
|
...location,
|
||||||
|
pathname: pathnames[location.pathname],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathname = location.pathname || '/';
|
||||||
|
pathname = pathname.trim().replace(/\/index\.html$/, '');
|
||||||
|
|
||||||
|
if (pathname === '') {
|
||||||
|
pathname = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
pathnames[location.pathname] = pathname;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...location,
|
||||||
|
pathname,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default normalizeLocation;
|
Loading…
Add table
Reference in a new issue