#How do I add onClick$ behavior to the <Link> component without it overriding the SPA nav behavior?
56 messages Β· Page 1 of 1 (latest)
You'd likely want to use a button instead, since that's the semantic element that expects an onClick$ handler. You can use the useNavigate hook, to take you to a specified URL programmatically.
It uses <Link /> internally as well.
but he has to keep in mind the browser wont know this is a link
No link should have an onClick$ handler π
But maybe it would work if a bunch of aria is used. Although that seems like the more difficult path haha
@bitter oar @waxen silo this is the more treacherous path but it is indeed possible if you really need it to be considered a link.
Nope, because they are both interactive elements that conflict with each other.
Much easier to do this
import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
export default component$(() => {
const nav = useNavigate();
return (
<button onClick$={() => nav('/about')}>About</button>
);
});
How would I then prefetch the page like I can do with <Link />?
Why do you need an onClick$ handler?
The page I'm developing is essentialy a search results page. I have a button which on click drops down a menu of some filter options. Clicking a filter option selects it (by changing one of the URL params). This stays on the same page, just with different URL params. But on click, I also want to close the dropdown menu.
Semantically, it is a link because its primary intent is to navigate to a new page
But if you're already navigating away from the page, why would you need to close the dropdown menu?
Does it stay between routes?
It's the same page, just different params
It's like /store/shirts/red to /store/shirts/blue
There's other state on the page that I want to preserve as the URL params change. Also, I want to prefetch the new page contents for optimal UX
Theoretically I could use something like useTask$() for this, but I generally find using async handlers like this (and useEffect in React) just to set state to be bad style as it creates too much "action at a distance". When the intent to change some state happens in response to some discrete, imperative action, I consider it best to handle in that action handler (in this case, an onClick$)
hm... is there any state that handles the opening and closing of the drop down menu?
Just this: const isOpen = useSignal(false);
I think a useTask$ or useComputed$ would make more sense here though. They are meant to track the changes of your state and do some work. onClick$ on the other hand is not meant to be on a link, unless you wanted to prevent the default behavior of the link
isOpen isn't derived from anything else here, so useComputed$ doesn't really make sense to use here
It's a "meant" to be a link as much as links are ever really meant to be links in the SPA context
maybe a track on the url params? I haven't had a similar use case
I think in SPAs you're generally overriding link behavior anyway
Well if the onClick$ is preventing you from overriding it, then it looks like you're going to have to recreate that behavior with preventDefault or use a task that tracks url params
onClick$ isn't preventing me from overriding the default behavior, it's overriding it and that's not what I want
I'm fine recreating it (that's why I was asking about prefetching above)
But I think this is arguably a bug in the framework. If you want to have an onClick$ property on the Link component, then it should happen in addition to the built-in behavior, not override it (otherwise, it's kinda just a div in disguise). If you don't want to allow overriding the behavior, then Link shouldn't have an onClick$ property
But at this point we're getting pretty subjective π
Anyway, thanks for your input!
I can see how it may look like it's a bug in the framework, but Qwik is just using the a tag under the hood. I believe this is how the native spec is.
Maybe you can add an onClick in Next.js and this will work I'm not sure, but from an accessibility perspective this is an anti pattern.
I'm also unsure of how prefetching is expected to work here, since doesn't Qwik do prefetching for you with speculative module fetching?
Qwik is using the a tag with an onClick$ prop under the hood: https://qwik.builder.io/docs/api/#link
I have to agree with Jack here, there's just something off about putting an onclick on an <a> tag. Saving state in the url is a good way to go about it, but I also think putting a track on the url params is the way to go. I think the reason why onClick works in React is that it's essentially just putting an event listener on the <a> tag that listens for a click.
Sure, I'll even agree that it's offputting as it seems semantically unclean, but this is how the framework itself chooses to handle it. And AFAICT there aren't any other options that achieve semantic purity without sacrificing UX (prefetching, a11y, URL in preview bar on hover, etc.)
I think you're talking about a different type of prefetching, see this thread: https://discord.com/channels/842438759945601056/1163140396717719623
But the framework does it to exactly stop normal behavior, right? You don't want to actually navigate and refresh page when ever you are clicking on a link component. That's why you use that one over the <a> tag.
Yes? All my thread here is asking is how I can add on to that onClick$ behavior instead of overriding it when I use the <Link/> component
If you really want the behavior to happen through an onClick I guess using the useNavigate would be the way to go. But just out of curiosity, is there any particular reason why you're avoiding the built in track for tracking state changes?
The code is more readable if all the effects of a click action are located in the same place
Also I think useTask$ might happen in a subsequent cycle/frame instead of the same cycle/frame? Haven't dug in deeply enough to know for sure
useTask$ is on the server until there is a tracked change, then it is on the client.
What does that have to do with something happening in the same refresh ?
And also Qwik as a framework seems to support this approach of adding onClick$ to an a tag since that's how they implemented the <Link /> component
One thing they could do (if they aren't already) in the link component, is this:
<a onClick$={[QwikLinkBehavior$, props.onClick$]} />
If they're not doing that, then that might be why you're having problems with onClick$ on the link component.
Yeah, exactly! That's what I proposed above. I had envisioned it more as just chucking it into the bottom of the existing onClick$ but yours is probably better since it's more order agnostic
I've also encountered enough race conditions when using useEffect in react (especially around routing) to be wary of using that hook when not necessary. I realize that useTask$ in Qwik is different, but I wouldn't be surprised at all if the same sorts of bugs show up
I wasn't aware that Qwik is using an onClick$ in the Link component π€ . I would add this change in a PR if you haven't. But first I would make sure that this solves your problem, you can pnpm link a pr with this change and try it in your project. Or just copy paste the component whatever works.
inside Link component in qwik city
onClick$={[WhateverQwikIsDoingHere$, props.onClick$]}
That's what I was saying up here π: #1163508799672438984 message
In case you're curious by the way, we already use the above pattern in Qwik UI to allow people to add their own additional behavior with event handlers.
For example, for some reason if they want to console log hi with an onClick$, we provide an array with our original QRL functionality, and then pass the onClick$ prop.