preact-router: Problems with link anchors

Whenever I click on a anchor link (for example ‘href=“#123”’), this

addEventListener('popstate', function () {
				routeTo(getCurrentUrl());
			});

fires and reloads the according route component, what some-have screws up the anchor and anyways is redundant.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Comments: 15 (4 by maintainers)

Most upvoted comments

Thanks for input @developit! But the native attribute only prevents the click handler to run and the route() and setUrl() to be called. It doesn’t prevent routeTo() to be called from the popstate handler. Which in turn leads to instance.setState() and instance.forceUpdate(). Is there a way to prevent this?

Hmm - no need for custom code here really - you can use the native prop to bypass preact-router for any link, including anchors. It’ll just use the browser’s default behavior:

<a href="#" native>Anchor link</a>

Before the fix is made in a PR, here is what I did to work around it - the core is DOM manipulation, not tied to any library. Hope it helps. But if you have shadow DOM with anchor, you need to write a custom query selector to walk the available shadow roots of the entire DOM to find the element.

Add the following manual scroll to any page.

export function useAnchor() {
  useEffect(() => {
    let scrollTop = 0;
    if (location.hash) {
      scrollTop = document.querySelector(location.hash).offsetTop;
    }
    window.scrollTo({ top: scrollTop });
  }, []);
}

@developit We are battle testing a fix in our fork. If successful, I’ll open a PR. I added the following line as the first line in the Router’s routeTo-method:

	/** Re-render children with a new URL to match against. */
	routeTo(url) {
		// marlun78: if url is unchanged or only the hash fragment changed, skip update
		if (typeof url!='string' || url.charAt(0)=='#' || this.state.url==url.replace(/#.*$/, '')) return false;

		this._didRoute = false;
		this.setState({ url });