Skip to content

Commit 69b1632

Browse files
taiontimdorr
authored andcommitted
Fix the withRef mess (#3740)
1 parent c6ac651 commit 69b1632

File tree

2 files changed

+69
-54
lines changed

2 files changed

+69
-54
lines changed

modules/__tests__/withRouter-test.js

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,17 @@ import { render, unmountComponentAtNode } from 'react-dom'
44
import createHistory from '../createMemoryHistory'
55
import Route from '../Route'
66
import Router from '../Router'
7-
import routerShape from '../PropTypes'
87
import withRouter from '../withRouter'
98

109
describe('withRouter', function () {
11-
class App extends Component {
12-
propTypes: {
13-
router: routerShape.isRequired
14-
}
15-
testFunction() {
16-
return 'hello from the test function'
17-
}
18-
render() {
19-
expect(this.props.router).toExist()
20-
return <h1>App</h1>
21-
}
10+
const routerStub = {
11+
push() {},
12+
replace() {},
13+
go() {},
14+
goBack() {},
15+
goForward() {},
16+
setRouteLeaveHook() {},
17+
isActive() {}
2218
}
2319

2420
let node
@@ -30,51 +26,63 @@ describe('withRouter', function () {
3026
unmountComponentAtNode(node)
3127
})
3228

33-
it('puts router on context', function (done) {
34-
const WrappedApp = withRouter(App)
29+
it('should put router on props', function (done) {
30+
const MyComponent = withRouter(({ router }) => {
31+
expect(router).toExist()
32+
done()
33+
return null
34+
})
35+
36+
function App() {
37+
return <MyComponent /> // Ensure no props are passed explicitly.
38+
}
3539

3640
render((
3741
<Router history={createHistory('/')}>
38-
<Route path="/" component={WrappedApp} />
42+
<Route path="/" component={App} />
3943
</Router>
40-
), node, function () {
41-
done()
42-
})
44+
), node)
4345
})
4446

45-
it('still uses router prop if provided', function (done) {
46-
const Test = withRouter(function (props) {
47-
props.test(props)
47+
it('should set displayName', function () {
48+
function MyComponent() {
4849
return null
49-
})
50-
const router = {
51-
push() {},
52-
replace() {},
53-
go() {},
54-
goBack() {},
55-
goForward() {},
56-
setRouteLeaveHook() {},
57-
isActive() {}
58-
}
59-
const test = function (props) {
60-
expect(props.router).toBe(router)
6150
}
6251

63-
render(<Test router={router} test={test} />, node, done)
52+
MyComponent.displayName = 'MyComponent'
53+
54+
expect(withRouter(MyComponent).displayName)
55+
.toEqual('withRouter(MyComponent)')
56+
})
57+
58+
it('should use router prop if specified', function (done) {
59+
const MyComponent = withRouter(({ router }) => {
60+
expect(router).toBe(routerStub)
61+
done()
62+
return null
63+
})
64+
65+
render(<MyComponent router={routerStub} />, node)
6466
})
6567

66-
it('should support withRefs as a parameter', function (done) {
67-
const WrappedApp = withRouter(App, { withRef: true })
68-
const router = {
69-
push() {},
70-
replace() {},
71-
go() {},
72-
goBack() {},
73-
goForward() {},
74-
setRouteLeaveHook() {},
75-
isActive() {}
68+
it('should support withRef', function () {
69+
const spy = expect.createSpy()
70+
71+
class MyComponent extends Component {
72+
invokeSpy() {
73+
spy()
74+
}
75+
76+
render() {
77+
return null
78+
}
7679
}
77-
const component = render((<WrappedApp router={router}/>), node, done)
78-
expect(component.getWrappedInstance().testFunction()).toEqual('hello from the test function')
80+
81+
const WrappedComponent = withRouter(MyComponent, { withRef: true })
82+
83+
const instance = render(<WrappedComponent router={routerStub} />, node)
84+
instance.getWrappedInstance().invokeSpy()
85+
86+
expect(spy).toHaveBeenCalled()
7987
})
8088
})

modules/withRouter.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,38 @@
1+
import invariant from 'invariant'
12
import React from 'react'
23
import hoistStatics from 'hoist-non-react-statics'
34
import { routerShape } from './PropTypes'
4-
import warning from './routerWarning'
5-
65

76
function getDisplayName(WrappedComponent) {
87
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
98
}
109

1110
export default function withRouter(WrappedComponent, options) {
12-
const { withRef } = options || {}
11+
const withRef = options && options.withRef
1312

1413
const WithRouter = React.createClass({
1514
contextTypes: { router: routerShape },
1615
propTypes: { router: routerShape },
1716

1817
getWrappedInstance() {
19-
warning(withRef, 'To access the wrappedInstance you must provide { withRef: true } as the second argument of the withRouter call')
20-
return this.wrappedComponent
18+
invariant(
19+
withRef,
20+
'To access the wrapped instance, you need to specify ' +
21+
'`{ withRef: true }` as the second argument of the withRouter() call.'
22+
)
23+
24+
return this.wrappedInstance
2125
},
2226

2327
render() {
24-
const { router, ...props } = this.props
28+
const router = this.props.router || this.context.router
29+
const props = { ...this.props, router }
2530

26-
if (withRef) props.ref = component =>this.wrappedComponent = component
31+
if (withRef) {
32+
props.ref = (c) => { this.wrappedInstance = c }
33+
}
2734

28-
return <WrappedComponent {...props} router={router || this.context.router} />
35+
return <WrappedComponent {...props} />
2936
}
3037
})
3138

0 commit comments

Comments
 (0)