Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f771154

Browse files
authored
Merge pull request #201 from v12/rr-v4
React Router v4 support
2 parents a7de1be + 32f9e44 commit f771154

11 files changed

+192
-198
lines changed

‎package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@
7373
"lodash": "^4.14.0",
7474
"mocha": "^2.5.3",
7575
"react": "^15.2.1",
76+
"react-addons-test-utils": "^15.4.2",
7677
"react-bootstrap": "^0.30.0",
7778
"react-dom": "^15.2.1",
78-
"react-router": "^2.6.0",
79+
"react-router-dom": "^4.0.0",
7980
"release-script": "^1.0.2",
8081
"rimraf": "^2.5.4",
8182
"shelljs": "^0.7.2",

‎src/IndexLinkContainer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import LinkContainer from './LinkContainer';
77
export default class IndexLinkContainer extends React.Component {
88
render() {
99
return (
10-
<LinkContainer {...this.props} onlyActiveOnIndex />
10+
<LinkContainer {...this.props} exact />
1111
);
1212
}
1313
}

‎src/LinkContainer.js

Lines changed: 90 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,46 @@
1-
// This is largely taken from react-router/lib/Link.
2-
3-
import React from 'react';
4-
5-
function isLeftClickEvent(event) {
6-
return event.button === 0;
7-
}
8-
9-
function isModifiedEvent(event) {
10-
return !!(
11-
event.metaKey ||
12-
event.altKey ||
13-
event.ctrlKey ||
14-
event.shiftKey
15-
);
16-
}
17-
18-
function createLocationDescriptor(to, query, hash, state) {
19-
if (query || hash || state) {
20-
return { pathname: to, query, hash, state };
21-
}
22-
23-
return to;
24-
}
25-
26-
const propTypes = {
27-
onlyActiveOnIndex: React.PropTypes.bool.isRequired,
28-
to: React.PropTypes.oneOfType([
29-
React.PropTypes.string,
30-
React.PropTypes.object,
31-
]).isRequired,
32-
query: React.PropTypes.string,
33-
hash: React.PropTypes.string,
34-
state: React.PropTypes.object,
35-
action: React.PropTypes.oneOf([
36-
'push',
37-
'replace',
38-
]).isRequired,
39-
onClick: React.PropTypes.func,
40-
active: React.PropTypes.bool,
41-
target: React.PropTypes.string,
42-
children: React.PropTypes.node.isRequired,
43-
};
1+
import React, { Component, PropTypes } from 'react';
2+
import { Route } from 'react-router-dom';
3+
4+
const isModifiedEvent = (event) =>
5+
!!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
6+
7+
export default class LinkContainer extends Component {
8+
static contextTypes = {
9+
router: PropTypes.shape({
10+
history: PropTypes.shape({
11+
push: PropTypes.func.isRequired,
12+
replace: PropTypes.func.isRequired,
13+
createHref: PropTypes.func.isRequired,
14+
}).isRequired,
15+
}).isRequired,
16+
};
4417

45-
const contextTypes = {
46-
router: React.PropTypes.object,
47-
};
18+
static propTypes = {
19+
children: PropTypes.element.isRequired,
20+
onClick: PropTypes.func,
21+
replace: PropTypes.bool,
22+
to: PropTypes.oneOfType([
23+
PropTypes.string,
24+
PropTypes.object,
25+
]).isRequired,
26+
exact: PropTypes.bool,
27+
strict: PropTypes.bool,
28+
className: PropTypes.string,
29+
activeClassName: PropTypes.string,
30+
style: PropTypes.object,
31+
activeStyle: PropTypes.object,
32+
isActive: PropTypes.func,
33+
};
4834

49-
const defaultProps = {
50-
onlyActiveOnIndex: false,
51-
action: 'push',
52-
};
35+
static defaultProps = {
36+
replace: false,
37+
exact: false,
38+
strict: false,
39+
activeClassName: 'active',
40+
};
5341

54-
class LinkContainer extends React.Component {
55-
onClick = (event) => {
56-
const {
57-
to, query, hash, state, children, onClick, target, action,
58-
} = this.props;
42+
handleClick = (event) => {
43+
const { children, onClick } = this.props;
5944

6045
if (children.props.onClick) {
6146
children.props.onClick(event);
@@ -66,42 +51,62 @@ class LinkContainer extends React.Component {
6651
}
6752

6853
if (
69-
target ||
70-
event.defaultPrevented ||
71-
isModifiedEvent(event) ||
72-
!isLeftClickEvent(event)
54+
!event.defaultPrevented && // onClick prevented default
55+
event.button === 0 && // ignore right clicks
56+
!isModifiedEvent(event) // ignore clicks with modifier keys
7357
) {
74-
return;
75-
}
58+
event.preventDefault();
7659

77-
event.preventDefault();
60+
const { history } = this.context.router;
61+
const { replace, to } = this.props;
7862

79-
this.context.router[action](
80-
createLocationDescriptor(to, query, hash, state)
81-
);
82-
};
63+
if (replace) {
64+
history.replace(to);
65+
} else {
66+
history.push(to);
67+
}
68+
}
69+
}
8370

8471
render() {
85-
const { router } = this.context;
86-
const { onlyActiveOnIndex, to, children, ...props } = this.props;
87-
88-
props.onClick = this.onClick;
89-
90-
// Ignore if rendered outside Router context; simplifies unit testing.
91-
if (router) {
92-
props.href = router.createHref(to);
72+
const {
73+
children,
74+
replace, // eslint-disable-line no-unused-vars
75+
to,
76+
exact,
77+
strict,
78+
activeClassName,
79+
className,
80+
activeStyle,
81+
style,
82+
isActive: getIsActive,
83+
...props,
84+
} = this.props;
9385

94-
if (props.active == null) {
95-
props.active = router.isActive(to, onlyActiveOnIndex);
96-
}
97-
}
86+
const href = this.context.router.history.createHref(
87+
typeof to === 'string' ? { pathname: to } : to
88+
);
9889

99-
return React.cloneElement(React.Children.only(children), props);
90+
return (
91+
<Route
92+
path={typeof to === 'object' ? to.pathname : to}
93+
exact={exact}
94+
strict={strict}
95+
children={({ location, match }) => {
96+
const isActive = !!(getIsActive ? getIsActive(match, location) : match);
97+
98+
return React.cloneElement(
99+
React.Children.only(children),
100+
{
101+
...props,
102+
className: isActive ? [className, activeClassName].join(' ') : className,
103+
style: isActive ? { ...style, ...activeStyle } : style,
104+
href,
105+
onClick: this.handleClick,
106+
}
107+
);
108+
}}
109+
/>
110+
);
100111
}
101112
}
102-
103-
LinkContainer.propTypes = propTypes;
104-
LinkContainer.contextTypes = contextTypes;
105-
LinkContainer.defaultProps = defaultProps;
106-
107-
export default LinkContainer;

‎test/IndexLinkContainer.spec.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from 'react';
2-
import ReactTestUtils from 'react/lib/ReactTestUtils';
2+
import ReactTestUtils from 'react-addons-test-utils';
33
import * as ReactBootstrap from 'react-bootstrap';
4-
import ReactDOM from 'react-dom';
5-
import { createMemoryHistory,IndexRoute,Route, Router } from 'react-router';
4+
import {findDOMNode} from 'react-dom';
5+
import { Route,MemoryRouteras Router } from 'react-router-dom';
66

77
import IndexLinkContainer from '../src/IndexLinkContainer';
88

@@ -19,25 +19,24 @@ describe('IndexLinkContainer', () => {
1919
describe('active state', () => {
2020
function renderComponent(location) {
2121
const router = ReactTestUtils.renderIntoDocument(
22-
<Router history={createMemoryHistory(location)}>
23-
<Route
24-
path="/"
25-
component={() => (
26-
<IndexLinkContainer to="/">
27-
<Component>Root</Component>
28-
</IndexLinkContainer>
29-
)}
30-
>
31-
<IndexRoute />
32-
<Route path="foo" />
33-
</Route>
22+
<Router initialEntries={[location]}>
23+
<div>
24+
<Route
25+
path="/"
26+
render={() => (
27+
<IndexLinkContainer to="/">
28+
<Component>Root</Component>
29+
</IndexLinkContainer>
30+
)}
31+
/>
32+
</div>
3433
</Router>
3534
);
3635

3736
const component = ReactTestUtils.findRenderedComponentWithType(
3837
router, Component
3938
);
40-
return ReactDOM.findDOMNode(component);
39+
return findDOMNode(component);
4140
}
4241

4342
it('should be active on the index route', () => {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /