#How do I add onClick$ behavior to the <Link> component without it overriding the SPA nav behavior?

56 messages Β· Page 1 of 1 (latest)

waxen silo
#

When I add an onClick$ to a <Link> component, clicking it no longer changes the page to the specified URL. Do I need to manually add the nav behavior myself or is there another way to do this?

clear crescent
#

It uses <Link /> internally as well.

bitter oar
clear crescent
#

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.

bitter oar
#

Could he wrap the button with a link?

#

And add the onclick to the button?

clear crescent
#

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>
  );
});
waxen silo
#

How would I then prefetch the page like I can do with <Link />?

clear crescent
waxen silo
#

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

clear crescent
#

Does it stay between routes?

waxen silo
#

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$)

clear crescent
waxen silo
#

Just this: const isOpen = useSignal(false);

clear crescent
#

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

waxen silo
#

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

clear crescent
#

maybe a track on the url params? I haven't had a similar use case

waxen silo
#

I think in SPAs you're generally overriding link behavior anyway

clear crescent
waxen silo
#

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!

clear crescent
# waxen silo But I think this is arguably a bug in the framework. If you want to have an `onC...

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?

waxen silo
stable wolf
#

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.

waxen silo
#

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.)

waxen silo
stable wolf
#

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.

waxen silo
#

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

stable wolf
#

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?

waxen silo
#

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

clear crescent
waxen silo
#

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

clear crescent
waxen silo
waxen silo
clear crescent
#

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$]}

clear crescent