Skip to content

Commit a38ef04

Browse files
StringEpsilontimdorr
authored andcommittedMay 16, 2019
Don't override path in NavLink component. Fixes #6613 (#6623)
* Don't override path in NavLink component. Fixes #6613 * Add tests for withRouter() inside NavLink * NavLink: Use RouterContext directly. Same reasons as for withRouter: Less nesting, clearer error message. * NavLink: Remove obsolete import. Updated size snapshot
1 parent 56c829b commit a38ef04

File tree

4 files changed

+99
-29
lines changed

4 files changed

+99
-29
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"esm/react-router-dom.js": {
3-
"bundled": 8159,
4-
"minified": 4903,
5-
"gzipped": 1641,
3+
"bundled": 8362,
4+
"minified": 5058,
5+
"gzipped": 1651,
66
"treeshaked": {
77
"rollup": {
88
"code": 453,
@@ -14,13 +14,13 @@
1414
}
1515
},
1616
"umd/react-router-dom.js": {
17-
"bundled": 159187,
18-
"minified": 56687,
19-
"gzipped": 16378
17+
"bundled": 159395,
18+
"minified": 56787,
19+
"gzipped": 16387
2020
},
2121
"umd/react-router-dom.min.js": {
22-
"bundled": 96042,
23-
"minified": 33707,
24-
"gzipped": 9946
22+
"bundled": 96151,
23+
"minified": 33747,
24+
"gzipped": 9951
2525
}
2626
}

‎packages/react-router-dom/modules/NavLink.js

+17-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from "react";
2-
import { Route } from "react-router";
2+
import { __RouterContext as RouterContext, matchPath } from "react-router";
33
import PropTypes from "prop-types";
4-
54
import Link from "./Link";
5+
import invariant from "tiny-invariant";
66

77
function joinClassnames(...classnames) {
88
return classnames.filter(i => i).join(" ");
@@ -18,7 +18,7 @@ function NavLink({
1818
className: classNameProp,
1919
exact,
2020
isActive: isActiveProp,
21-
location,
21+
location: locationProp,
2222
strict,
2323
style: styleProp,
2424
to,
@@ -30,14 +30,18 @@ function NavLink({
3030
const escapedPath = path && path.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
3131

3232
return (
33-
<Route
34-
path={escapedPath}
35-
exact={exact}
36-
strict={strict}
37-
location={location}
38-
children={({ location, match }) => {
33+
<RouterContext.Consumer>
34+
{context => {
35+
invariant(context, "You should not use <NavLink> outside a <Router>");
36+
37+
const pathToMatch = locationProp
38+
? locationProp.pathname
39+
: context.location.pathname;
40+
const match = escapedPath
41+
? matchPath(pathToMatch, { path: escapedPath, exact, strict })
42+
: null;
3943
const isActive = !!(isActiveProp
40-
? isActiveProp(match, location)
44+
? isActiveProp(match, context.location)
4145
: match);
4246

4347
const className = isActive
@@ -55,7 +59,7 @@ function NavLink({
5559
/>
5660
);
5761
}}
58-
/>
62+
</RouterContext.Consumer>
5963
);
6064
}
6165

@@ -75,10 +79,10 @@ if (__DEV__) {
7579
activeClassName: PropTypes.string,
7680
activeStyle: PropTypes.object,
7781
className: PropTypes.string,
78-
exact: Route.propTypes.exact,
82+
exact: PropTypes.bool,
7983
isActive: PropTypes.func,
8084
location: PropTypes.object,
81-
strict: Route.propTypes.strict,
85+
strict: PropTypes.bool,
8286
style: PropTypes.object
8387
};
8488
}

‎packages/react-router-dom/modules/__tests__/NavLink-test.js

+67-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from "react";
22
import ReactDOM from "react-dom";
3-
import { MemoryRouter, NavLink, withRouter } from "react-router-dom";
3+
import { MemoryRouter, NavLink, withRouter, Route } from "react-router-dom";
44

55
import renderStrict from "./utils/renderStrict";
66

@@ -487,4 +487,70 @@ describe("A <NavLink>", () => {
487487
expect(a.className).not.toContain("active");
488488
});
489489
});
490+
491+
describe("doesn't interfere with withRouter", () => {
492+
let props;
493+
494+
const PropsChecker = withRouter(p => {
495+
props = p;
496+
return null;
497+
});
498+
499+
beforeEach(() => {
500+
props = null;
501+
});
502+
503+
it("allows withRouter to access the correct match without route", () => {
504+
renderStrict(
505+
<MemoryRouter initialEntries={["/pizza/"]}>
506+
<NavLink to="/pizza/">
507+
<PropsChecker />
508+
</NavLink>
509+
</MemoryRouter>,
510+
node
511+
);
512+
513+
expect(props.match).not.toBeNull();
514+
expect(props.match.url).toBe("/");
515+
});
516+
517+
it("allows withRouter to access the correct match inside a route", () => {
518+
renderStrict(
519+
<MemoryRouter initialEntries={["/pizza/"]}>
520+
<Route
521+
path="/pizza"
522+
component={() => (
523+
<NavLink to="/pizza/">
524+
<PropsChecker />
525+
</NavLink>
526+
)}
527+
/>
528+
</MemoryRouter>,
529+
node
530+
);
531+
532+
expect(props.match).not.toBeNull();
533+
expect(props.match.url).toBe("/pizza/");
534+
});
535+
536+
it("allows withRouter to access the correct match with params inside a route", () => {
537+
renderStrict(
538+
<MemoryRouter initialEntries={["/pizza/cheese"]}>
539+
<Route
540+
path="/pizza/:topping"
541+
component={() => (
542+
<NavLink to="/pizza/">
543+
<PropsChecker />
544+
</NavLink>
545+
)}
546+
/>
547+
</MemoryRouter>,
548+
node
549+
);
550+
551+
expect(props.match).not.toBeNull();
552+
expect(props.match.url).toBe("/pizza/cheese");
553+
expect(props.match.params).toEqual({ topping: "cheese" });
554+
});
555+
});
490556
});

‎packages/react-router/.size-snapshot.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"esm/react-router.js": {
3-
"bundled": 23463,
4-
"minified": 13259,
5-
"gzipped": 3684,
3+
"bundled": 23522,
4+
"minified": 13316,
5+
"gzipped": 3688,
66
"treeshaked": {
77
"rollup": {
88
"code": 2356,
@@ -14,9 +14,9 @@
1414
}
1515
},
1616
"umd/react-router.js": {
17-
"bundled": 99114,
18-
"minified": 35078,
19-
"gzipped": 11239
17+
"bundled": 99173,
18+
"minified": 35111,
19+
"gzipped": 11242
2020
},
2121
"umd/react-router.min.js": {
2222
"bundled": 61717,

0 commit comments

Comments
 (0)
Please sign in to comment.