mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
fix: Forces Link to expose the href to the child using passHref property. (#2503)
* Forces Link to exposes the href to the child using passHref property. * tests for passHref prop of the Link * passHref property Link documentation
This commit is contained in:
parent
a3495b364d
commit
6e7ac5f0ef
|
@ -27,7 +27,8 @@ export default class Link extends Component {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
shallow: PropTypes.bool
|
shallow: PropTypes.bool,
|
||||||
|
passHref: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
|
@ -121,8 +122,9 @@ export default class Link extends Component {
|
||||||
onClick: this.linkClicked
|
onClick: this.linkClicked
|
||||||
}
|
}
|
||||||
|
|
||||||
// If child is an <a> tag and doesn't have a href attribute we specify it so that repetition is not needed by the user
|
// If child is an <a> tag and doesn't have a href attribute, or if the 'passHref' property is
|
||||||
if (child.type === 'a' && !('href' in child.props)) {
|
// defined, we specify the current 'href', so that repetition is not needed by the user
|
||||||
|
if (this.props.passHref || (child.type === 'a' && !('href' in child.props))) {
|
||||||
props.href = as || href
|
props.href = as || href
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
readme.md
15
readme.md
|
@ -357,6 +357,21 @@ export default () => (
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Forcing the Link to expose `href` to its child
|
||||||
|
|
||||||
|
If child is an `<a>` tag and doesn't have a href attribute we specify it so that the repetition is not needed by the user. However, sometimes, you’ll want to pass an `<a>` tag inside of a wrapper and the `Link` won’t recognize it as a *hiperlink*, and, consequently, won’t transfer its `href` to the child. In cases like that, you should define a boolean `passHref` property to the `Link`, forcing it to expose its `href` property to the child.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Unexpected_A from 'third-library'
|
||||||
|
|
||||||
|
export default ({ href, name }) => (
|
||||||
|
<Link href={ href } passHref>
|
||||||
|
<Unexpected_A>{ name }</Unexpected_A>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
#### Imperatively
|
#### Imperatively
|
||||||
|
|
||||||
<p><details>
|
<p><details>
|
||||||
|
|
27
test/integration/basic/pages/nav/pass-href-prop.js
Normal file
27
test/integration/basic/pages/nav/pass-href-prop.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
const UnexpectedNestedA = () => {
|
||||||
|
const UnexpectedWrapper = (props) => {
|
||||||
|
const {href, id} = props
|
||||||
|
const safeProps = {href, id}
|
||||||
|
return (<a {...safeProps}>{props.children}</a>)
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnexpectedWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
const FakeA = UnexpectedNestedA()
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div className='nav-pass-href-prop'>
|
||||||
|
<Link href='/nav' passHref>
|
||||||
|
<FakeA id='with-href'>Will redirect as an `a` tag</FakeA>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link href='/nav'>
|
||||||
|
<FakeA id='without-href'>Will not redirect as an `a` tag</FakeA>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<p>This is the passHref prop page.</p>
|
||||||
|
</div>
|
||||||
|
)
|
|
@ -45,6 +45,30 @@ export default (context, render) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('with unexpected <a/> nested tag', () => {
|
||||||
|
it('should not redirect if passHref prop is not defined in Link', async () => {
|
||||||
|
const browser = await webdriver(context.appPort, '/nav/pass-href-prop')
|
||||||
|
const text = await browser
|
||||||
|
.elementByCss('#without-href').click()
|
||||||
|
.waitForElementByCss('.nav-pass-href-prop')
|
||||||
|
.elementByCss('p').text()
|
||||||
|
|
||||||
|
expect(text).toBe('This is the passHref prop page.')
|
||||||
|
browser.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should redirect if passHref prop is defined in Link', async () => {
|
||||||
|
const browser = await webdriver(context.appPort, '/nav/pass-href-prop')
|
||||||
|
const text = await browser
|
||||||
|
.elementByCss('#with-href').click()
|
||||||
|
.waitForElementByCss('.nav-home')
|
||||||
|
.elementByCss('p').text()
|
||||||
|
|
||||||
|
expect(text).toBe('This is the home.')
|
||||||
|
browser.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('with empty getInitialProps()', () => {
|
describe('with empty getInitialProps()', () => {
|
||||||
it('should render an error', async () => {
|
it('should render an error', async () => {
|
||||||
const browser = await webdriver(context.appPort, '/nav')
|
const browser = await webdriver(context.appPort, '/nav')
|
||||||
|
|
Loading…
Reference in a new issue