Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added applyRouterMiddleware #3327

Merged
merged 1 commit into from
Apr 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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