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
Consider handling onClick on next/link elements #1490
Comments
This is not a good API generally. Because it's not sure what you could do with that handler since the page is already changing to the new route. I get the point of onClick and why you need to use that. |
@arunoda The |
Not a good API generally is: Silently overriding mechanisms of an established API, subverting users expectations and preventing default behavior. Consider a solution like this (in linkClicked(e){
const child = Children.only(this.props.children)
if (child.props.onClick) child.props.onClick(e)
if (e.defaultPrevented) return
// do your thing ...
}
render(){
// irrelevant parts omitted ...
const child = Children.only(children)
const props = {
onClick: this.linkClicked
}
return React.cloneElement(child, props)
} |
@ehd do you mind sharing that wicked way? :) |
Courtesy of the great @janv: import Link from 'next/link'
import React from 'react'
// This is the custom wrapper component you would build and use just like `next/link`:
class MyLink extends React.Component {
render () {
const { onCustomClick, ...props } = this.props
return <a {...props} onClick={this.handleClick} />
}
handleClick = event => {
if (this.props.onClick) {
this.props.onClick(event)
}
if (this.props.onCustomClick) {
this.props.onCustomClick(event)
}
}
}
// This is some example where you would use `MyLink` including a click handler
export default class SomeComponent extends React.Component {
render () {
return <div>
<Link href='/hello'>
<MyLink onCustomClick={() => alert('lol')}>
LinkText
</MyLink>
</Link>
</div>
}
} |
@arunoda I have another use case with the documentation of Material-UI. I want to close the Drawer right after the user link interaction, waiting for the new page to load. I'm gonna use the component middleware hack for now (I believe that the issue should be opened). |
ahh bollocks i couldn't get the wickedness to work... here's how I'm doing it unsuccessfully:
with a good ol
he'll I even tried
|
I too think this should behave naturally, here is my work-around that doesn't need custom component: <Link href='/hello'>
<div>
<a onClick={() => {customFuntionCall()}}>
LinkText
</a>
</div>
</Link> Since Hope this helps 😄 |
This has tripped me up a couple times already. I agree that there needs to be a non-hacky way to attach click handlers to links. Analytics tracking is a common use case. At the very least a warning should be thrown, instead of just silently overriding it. |
I would also like to see this issue reopened. In my case I have a dropdown with links, and I want to close the dropdown when clicking on a link. I can get work around it, but proper support for onClick would be nice! |
I think this is especially useful if the |
It can also be useful to show a loader on screen (this.setState({loading: true}) while the other page loads |
Here's what I've been doing: import React, { Component } from 'react'
import Router from 'next/router'
export default class MyLink extends Component {
componentDidMount () {
Router.prefetch(this.props.url)
}
render() {
const { url, asUrl, children, onClick } = this['props']
return (
<a href={asUrl} onClick={(event) => {
event.preventDefault()
onClick()
Router.push(url, asUrl)
}}>
{children}
</a>
)
}
} I'm not sure about performance issues though. |
@viniciusCamargo how are you handling |
Hey @paschalidi, unfortunately, I'm not handling it, I didn't have the time to try to fix it yet. Edit: btw, if you have any idea for a fix I'd appreciate. |
@arunoda what if we have to implement some validations on onClick function before login? |
Link is so much more powerful than Router (preloading, smart handling in linkClicked) that it's painful to have to duplicate that logic outside of Link to make this work. I have the same use case as @oliviertassinari - I need to close my Material UI drawer :) @CorwinCZ's workaround is great. Just need to add a |
CorwinCZ's work around works, but I had problems with the URL not showing in the browser when you hover over the link, and also styling was slightly more complicated (my links were inline elements and the export const NavLink = ({page, params, onClick=()=>{}, children}) => {
return (
<li>
<Link {...Router.linkPage(page, params)} passHref prefetch>
<a>
<span onClick={onClick}>
{children}
</span>
</a>
</Link>
</li>
)
}; This shows the pointer by default when mousing over a link and doesn't create block elements in your links. Edited: Removed redundant functional wrapper as suggested by @JonAbrams. |
Thanks @ckeeney, your solution worked great for me, but I simplified my span like so: One remaining small downside is the |
Should this be reopened? |
Allow `onClick` on `next/link` child. This should not be a breaking change, but it's a very useful feature. Real-life use cases include: analytics or closing menu on navigation, and other. - [x] allow optional `onClick` on `next/link` component's child - [x] call original `child.props.onClick(e)` before `this.linkClicked(e)` - [x] add integration tests - [x] cancel the navigation if `e.defaultPrevented === true` Fixes #1490
Guess it should based on the many upvotes. |
It's already out on canary, so re-opening is not needed. https://github.com/zeit/next.js/releases |
Thank you all! |
Allow `onClick` on `next/link` child. This should not be a breaking change, but it's a very useful feature. Real-life use cases include: analytics or closing menu on navigation, and other. - [x] allow optional `onClick` on `next/link` component's child - [x] call original `child.props.onClick(e)` before `this.linkClicked(e)` - [x] add integration tests - [x] cancel the navigation if `e.defaultPrevented === true` Fixes vercel#1490
Currently
next/link
will ignoreonClick
props set on<Link>
or contained<a>
elements:Clicking either of those two links will not call the
customHandleClick
function.This is because the
onClick
handler of the contained<a>
tag is overridden by thenext/link
implementation here.If this were to be changed a good way would be checking for, and calling, the
onClick
prop passed to the<Link>
element as part of its internal click handler. See react-router’s Link element for inspiration.Why I would consider changing this:
onClick
handlers on links can be useful for various things, but mostly I didn’t expect that theonClick
wasn’t being called at all. I’ve added support for this to my customLink
element, but I thinkonClick
"should just work".The text was updated successfully, but these errors were encountered: