Skip to content

Commit

Permalink
added applyRouterMiddleware
Browse files Browse the repository at this point in the history
closes #3316
  • Loading branch information
ryanflorence authored and timdorr committed Apr 15, 2016
1 parent c84d267 commit 28f449f
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 1 deletion.
10 changes: 9 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## [HEAD]
> Unreleased
- **Feature:** Added `applyRouterMiddleware` ([#3327])

[HEAD]: https://github.com/reactjs/react-router/compare/v2.2.4...master
[#3327]: https://github.com/reactjs/react-router/issues/3327

## [v2.2.4]
> April 15, 2016
Expand All @@ -13,8 +21,8 @@
- **Minor:** Speed up checking index path active status ([#3313])

[v2.2.3]: https://github.com/reactjs/react-router/compare/v2.2.2...v2.2.3
[#3313]: https://github.com/reactjs/react-router/pull/3313
[#3331]: https://github.com/reactjs/react-router/pull/3331
[#3313]: https://github.com/reactjs/react-router/pull/3313


## [v2.2.2]
Expand Down
144 changes: 144 additions & 0 deletions modules/__tests__/applyRouterMiddleware-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import expect from 'expect'
import React, { cloneElement } from 'react'
import { render } from 'react-dom'
import Router from '../Router'
import Route from '../Route'
import createMemoryHistory from '../createMemoryHistory'
import applyMiddleware from '../applyRouterMiddleware'

const FOO_ROOT_CONTAINER_TEXT = 'FOO ROOT CONTAINER'
const BAR_ROOT_CONTAINER_TEXT = 'BAR ROOT CONTAINER'
const BAZ_CONTAINER_TEXT = 'BAZ INJECTED'

const FooRootContainer = React.createClass({
propTypes: { children: React.PropTypes.node.isRequired },
childContextTypes: { foo: React.PropTypes.string },
getChildContext() { return { foo: FOO_ROOT_CONTAINER_TEXT } },
render() {
return this.props.children
}
})

const FooContainer = React.createClass({
propTypes: { children: React.PropTypes.node.isRequired },
contextTypes: { foo: React.PropTypes.string.isRequired },
render() {
const { children, ...props } = this.props
const fooFromContext = this.context.foo
return cloneElement(children, { ...props, fooFromContext })
}
})

const useFoo = () => ({
renderRouterContext: (child) => (
<FooRootContainer>{child}</FooRootContainer>
),
renderRouteComponent: (child) => (
<FooContainer>{child}</FooContainer>
)
})

const BarRootContainer = React.createClass({
propTypes: { children: React.PropTypes.node.isRequired },
childContextTypes: { bar: React.PropTypes.string },
getChildContext() { return { bar: BAR_ROOT_CONTAINER_TEXT } },
render() {
return this.props.children
}
})

const BarContainer = React.createClass({
propTypes: { children: React.PropTypes.node.isRequired },
contextTypes: { bar: React.PropTypes.string.isRequired },
render() {
const { children, ...props } = this.props
const barFromContext = this.context.bar
return cloneElement(children, { props, barFromContext })
}
})

const useBar = () => ({
renderRouterContext: (child) => (
<BarRootContainer>{child}</BarRootContainer>
),
renderRouteComponent: (child) => (
<BarContainer>{child}</BarContainer>
)
})

const useBaz = (bazInjected) => ({
renderRouteComponent: (child) => (
cloneElement(child, { bazInjected })
)
})

const run = ({ renderWithMiddleware, Component }, assertion) => {
const div = document.createElement('div')
const routes = <Route path="/" component={Component}/>
render(<Router
render={renderWithMiddleware}
routes={routes}
history={createMemoryHistory('/')}
/>, div, () => assertion(div.innerHTML))
}

describe('applyMiddleware', () => {

it('applies one middleware', (done) => {
run({
renderWithMiddleware: applyMiddleware(useFoo()),
Component: (props) => <div>{props.fooFromContext}</div>
}, (html) => {
expect(html).toContain(FOO_ROOT_CONTAINER_TEXT)
done()
})
})

it('applies more than one middleware', (done) => {
run({
renderWithMiddleware: applyMiddleware(useBar(), useFoo()),
Component: (props) => <div>{props.fooFromContext} {props.barFromContext}</div>
}, (html) => {
expect(html).toContain(FOO_ROOT_CONTAINER_TEXT)
expect(html).toContain(BAR_ROOT_CONTAINER_TEXT)
done()
})
})

it('applies more middleware with only `getContainer`', (done) => {
run({
renderWithMiddleware: applyMiddleware(
useBar(),
useFoo(),
useBaz(BAZ_CONTAINER_TEXT)
),
Component: (props) => (
<div>
{props.fooFromContext}
{props.barFromContext}
{props.bazInjected}
</div>
)
}, (html) => {
expect(html).toContain(FOO_ROOT_CONTAINER_TEXT)
expect(html).toContain(BAR_ROOT_CONTAINER_TEXT)
expect(html).toContain(BAZ_CONTAINER_TEXT)
done()
})
})

it('applies middleware that only has `getContainer`', (done) => {
run({
renderWithMiddleware: applyMiddleware(
useBaz(BAZ_CONTAINER_TEXT)
),
Component: (props) => (
<div>{props.bazInjected}</div>
)
}, (html) => {
expect(html).toContain(BAZ_CONTAINER_TEXT)
done()
})
})

})
30 changes: 30 additions & 0 deletions modules/applyRouterMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { createElement } from 'react'
import RouterContext from './RouterContext'

export default (...middlewares) => {
const withContext = middlewares.map(m => m.renderRouterContext).filter(f => f)
const withComponent = middlewares.map(m => m.renderRouteComponent).filter(f => f)
const makeCreateElement = (baseCreateElement = createElement) => (
(Component, props) => (
withComponent.reduceRight(
(previous, renderRouteComponent) => (
renderRouteComponent(previous, props)
), baseCreateElement(Component, props)
)
)
)

return (renderProps) => (
withContext.reduceRight(
(previous, renderRouterContext) => (
renderRouterContext(previous, renderProps)
), (
<RouterContext
{...renderProps}
createElement={makeCreateElement(renderProps.createElement)}
/>
)
)
)
}

1 change: 1 addition & 0 deletions modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export PropTypes from './PropTypes'
export match from './match'
export useRouterHistory from './useRouterHistory'
export { formatPattern } from './PatternUtils'
export applyRouterMiddleware from './applyRouterMiddleware'

/* histories */
export browserHistory from './browserHistory'
Expand Down

0 comments on commit 28f449f

Please sign in to comment.