Skip to content

Commit

Permalink
Add support for function to (#3669)
Browse files Browse the repository at this point in the history
  • Loading branch information
taion authored and timdorr committed Jul 26, 2016
1 parent 640f751 commit f676dcb
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
19 changes: 13 additions & 6 deletions modules/Link.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ function isEmptyObject(object) {
return true
}

function resolveToLocation(to, router) {
return typeof to === 'function' ? to(router.location) : to
}

/**
* A <Link> is used to create an <a> element that links to a route.
* When that route is active, the link gets the value of its
Expand Down Expand Up @@ -49,7 +53,7 @@ const Link = React.createClass({
},

propTypes: {
to: oneOfType([ string, object ]).isRequired,
to: oneOfType([ string, object, func ]).isRequired,
query: object,
hash: string,
state: object,
Expand All @@ -74,8 +78,9 @@ const Link = React.createClass({
if (event.defaultPrevented)
return

const { router } = this.context
invariant(
this.context.router,
router,
'<Link>s rendered outside of a router context cannot navigate.'
)

Expand All @@ -89,19 +94,21 @@ const Link = React.createClass({

event.preventDefault()

this.context.router.push(this.props.to)
router.push(resolveToLocation(this.props.to, router))
},

render() {
const { to, activeClassName, activeStyle, onlyActiveOnIndex, ...props } = this.props
// Ignore if rendered outside the context of router, simplifies unit testing.

// Ignore if rendered outside the context of router to simplify unit testing.
const { router } = this.context

if (router) {
props.href = router.createHref(to)
const toLocation = resolveToLocation(to, router)
props.href = router.createHref(toLocation)

if (activeClassName || (activeStyle != null && !isEmptyObject(activeStyle))) {
if (router.isActive(to, onlyActiveOnIndex)) {
if (router.isActive(toLocation, onlyActiveOnIndex)) {
if (activeClassName) {
if (props.className) {
props.className += ` ${activeClassName}`
Expand Down
43 changes: 43 additions & 0 deletions modules/__tests__/Link-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,47 @@ describe('A <Link>', () => {
})
})

describe('with function to', () => {
const LinkWrapper = () => (
<Link
to={location => ({ ...location, hash: '#hash' })}
activeClassName="active"
>
Link
</Link>
)

it('should have the correct href and active state', () => {
render((
<Router history={createHistory('/hello')}>
<Route path="/hello" component={LinkWrapper} />
</Router>
), node, () => {
const a = node.querySelector('a')
expect(a.getAttribute('href')).toEqual('/hello#hash')
expect(a.className.trim()).toEqual('active')
})
})

it('should transition correctly on click', done => {
const steps = [
() => {
click(node.querySelector('a'), { button: 0 })
},
({ location }) => {
expect(location.pathname).toEqual('/hello')
expect(location.hash).toEqual('#hash')
}
]

const execNextStep = execSteps(steps, done)

render((
<Router history={createHistory('/hello')} onUpdate={execNextStep}>
<Route path="/hello" component={LinkWrapper} />
</Router>
), node, execSteps)
})
})

})

0 comments on commit f676dcb

Please sign in to comment.