Skip to content

Commit 4c6a834

Browse files
ryanflorencetaion
authored andcommitted
added applyRouterMiddleware (#3327)
closes #3316
1 parent c84d267 commit 4c6a834

File tree

4 files changed

+184
-1
lines changed

4 files changed

+184
-1
lines changed

CHANGES.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## [HEAD]
2+
> Unreleased
3+
4+
- **Feature:** Added `applyRouterMiddleware` ([#3327])
5+
6+
[HEAD]: https://github.com/reactjs/react-router/compare/v2.2.4...master
7+
[#3327]: https://github.com/reactjs/react-router/issues/3327
8+
19
## [v2.2.4]
210
> April 15, 2016
311
@@ -13,8 +21,8 @@
1321
- **Minor:** Speed up checking index path active status ([#3313])
1422

1523
[v2.2.3]: https://github.com/reactjs/react-router/compare/v2.2.2...v2.2.3
16-
[#3313]: https://github.com/reactjs/react-router/pull/3313
1724
[#3331]: https://github.com/reactjs/react-router/pull/3331
25+
[#3313]: https://github.com/reactjs/react-router/pull/3313
1826

1927

2028
## [v2.2.2]
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import expect from 'expect'
2+
import React, { cloneElement } from 'react'
3+
import { render } from 'react-dom'
4+
import Router from '../Router'
5+
import Route from '../Route'
6+
import createMemoryHistory from '../createMemoryHistory'
7+
import applyMiddleware from '../applyRouterMiddleware'
8+
9+
const FOO_ROOT_CONTAINER_TEXT = 'FOO ROOT CONTAINER'
10+
const BAR_ROOT_CONTAINER_TEXT = 'BAR ROOT CONTAINER'
11+
const BAZ_CONTAINER_TEXT = 'BAZ INJECTED'
12+
13+
const FooRootContainer = React.createClass({
14+
propTypes: { children: React.PropTypes.node.isRequired },
15+
childContextTypes: { foo: React.PropTypes.string },
16+
getChildContext() { return { foo: FOO_ROOT_CONTAINER_TEXT } },
17+
render() {
18+
return this.props.children
19+
}
20+
})
21+
22+
const FooContainer = React.createClass({
23+
propTypes: { children: React.PropTypes.node.isRequired },
24+
contextTypes: { foo: React.PropTypes.string.isRequired },
25+
render() {
26+
const { children, ...props } = this.props
27+
const fooFromContext = this.context.foo
28+
return cloneElement(children, { ...props, fooFromContext })
29+
}
30+
})
31+
32+
const useFoo = () => ({
33+
renderRouterContext: (child) => (
34+
<FooRootContainer>{child}</FooRootContainer>
35+
),
36+
renderRouteComponent: (child) => (
37+
<FooContainer>{child}</FooContainer>
38+
)
39+
})
40+
41+
const BarRootContainer = React.createClass({
42+
propTypes: { children: React.PropTypes.node.isRequired },
43+
childContextTypes: { bar: React.PropTypes.string },
44+
getChildContext() { return { bar: BAR_ROOT_CONTAINER_TEXT } },
45+
render() {
46+
return this.props.children
47+
}
48+
})
49+
50+
const BarContainer = React.createClass({
51+
propTypes: { children: React.PropTypes.node.isRequired },
52+
contextTypes: { bar: React.PropTypes.string.isRequired },
53+
render() {
54+
const { children, ...props } = this.props
55+
const barFromContext = this.context.bar
56+
return cloneElement(children, { props, barFromContext })
57+
}
58+
})
59+
60+
const useBar = () => ({
61+
renderRouterContext: (child) => (
62+
<BarRootContainer>{child}</BarRootContainer>
63+
),
64+
renderRouteComponent: (child) => (
65+
<BarContainer>{child}</BarContainer>
66+
)
67+
})
68+
69+
const useBaz = (bazInjected) => ({
70+
renderRouteComponent: (child) => (
71+
cloneElement(child, { bazInjected })
72+
)
73+
})
74+
75+
const run = ({ renderWithMiddleware, Component }, assertion) => {
76+
const div = document.createElement('div')
77+
const routes = <Route path="/" component={Component}/>
78+
render(<Router
79+
render={renderWithMiddleware}
80+
routes={routes}
81+
history={createMemoryHistory('/')}
82+
/>, div, () => assertion(div.innerHTML))
83+
}
84+
85+
describe('applyMiddleware', () => {
86+
87+
it('applies one middleware', (done) => {
88+
run({
89+
renderWithMiddleware: applyMiddleware(useFoo()),
90+
Component: (props) => <div>{props.fooFromContext}</div>
91+
}, (html) => {
92+
expect(html).toContain(FOO_ROOT_CONTAINER_TEXT)
93+
done()
94+
})
95+
})
96+
97+
it('applies more than one middleware', (done) => {
98+
run({
99+
renderWithMiddleware: applyMiddleware(useBar(), useFoo()),
100+
Component: (props) => <div>{props.fooFromContext} {props.barFromContext}</div>
101+
}, (html) => {
102+
expect(html).toContain(FOO_ROOT_CONTAINER_TEXT)
103+
expect(html).toContain(BAR_ROOT_CONTAINER_TEXT)
104+
done()
105+
})
106+
})
107+
108+
it('applies more middleware with only `getContainer`', (done) => {
109+
run({
110+
renderWithMiddleware: applyMiddleware(
111+
useBar(),
112+
useFoo(),
113+
useBaz(BAZ_CONTAINER_TEXT)
114+
),
115+
Component: (props) => (
116+
<div>
117+
{props.fooFromContext}
118+
{props.barFromContext}
119+
{props.bazInjected}
120+
</div>
121+
)
122+
}, (html) => {
123+
expect(html).toContain(FOO_ROOT_CONTAINER_TEXT)
124+
expect(html).toContain(BAR_ROOT_CONTAINER_TEXT)
125+
expect(html).toContain(BAZ_CONTAINER_TEXT)
126+
done()
127+
})
128+
})
129+
130+
it('applies middleware that only has `getContainer`', (done) => {
131+
run({
132+
renderWithMiddleware: applyMiddleware(
133+
useBaz(BAZ_CONTAINER_TEXT)
134+
),
135+
Component: (props) => (
136+
<div>{props.bazInjected}</div>
137+
)
138+
}, (html) => {
139+
expect(html).toContain(BAZ_CONTAINER_TEXT)
140+
done()
141+
})
142+
})
143+
144+
})

modules/applyRouterMiddleware.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { createElement } from 'react'
2+
import RouterContext from './RouterContext'
3+
4+
export default (...middlewares) => {
5+
const withContext = middlewares.map(m => m.renderRouterContext).filter(f => f)
6+
const withComponent = middlewares.map(m => m.renderRouteComponent).filter(f => f)
7+
const makeCreateElement = (baseCreateElement = createElement) => (
8+
(Component, props) => (
9+
withComponent.reduceRight(
10+
(previous, renderRouteComponent) => (
11+
renderRouteComponent(previous, props)
12+
), baseCreateElement(Component, props)
13+
)
14+
)
15+
)
16+
17+
return (renderProps) => (
18+
withContext.reduceRight(
19+
(previous, renderRouterContext) => (
20+
renderRouterContext(previous, renderProps)
21+
), (
22+
<RouterContext
23+
{...renderProps}
24+
createElement={makeCreateElement(renderProps.createElement)}
25+
/>
26+
)
27+
)
28+
)
29+
}
30+

modules/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export PropTypes from './PropTypes'
2323
export match from './match'
2424
export useRouterHistory from './useRouterHistory'
2525
export { formatPattern } from './PatternUtils'
26+
export applyRouterMiddleware from './applyRouterMiddleware'
2627

2728
/* histories */
2829
export browserHistory from './browserHistory'

0 commit comments

Comments
 (0)