NextJs 13 Experimental App Dir Hash в маршрутах, не направляющих на хэш-идентификатор

Я использую Nextjs 13 с экспериментальным App Dir, но не уверен, что эта проблема, с которой я сталкиваюсь, имеет какое-либо отношение к проблеме, с которой я сталкиваюсь. У меня есть идентификатор на моей домашней странице «Часто задаваемые вопросы», и когда я нажимаю на ссылку, я вижу, что она успешно переходит по этой ссылке, но ничего не делает в браузере. Если я нахожусь на другой странице, я нажимаю на ссылку, и она перенаправляет меня на домашнюю страницу с правильным URL-адресом, но все еще остается в верхней части страницы и не прокручивается до указанного идентификатора. я реализовалscroll={false}как предлагается в документации, но это не имеет значения.

Вот фрагмент соответствующих частей кода:

      "use client"
import React, { useState } from "react"
import { useRouter } from "next/navigation"
import Link from "next/link"

const Navigation = () => {
  const router = useRouter()
 ...

В ответ:

       <Link scroll={false} href="/#faqs">FAQS</Link>

Я даже пробовал:

      <button type="button" onClick={() => router.push("/#faqs")}>FAQS</button>

В React хэш работает довольно хорошо, но в next js даже только при клиентском рендеринге он кажется запутанным. Если кто-нибудь знает, что я делаю неправильно или есть жизнеспособная работа, я был бы очень признателен. Заранее спасибо. Если я что-то упустил, пожалуйста, дайте мне знать.

3 ответа

Я часто использую хэштеги и планирую начать использовать каталог приложений в будущих проектах, поэтому я покопался в этом, и это некрасиво. Судя по всему, NextJS использует другой пакет для компонентов каталога приложений на стороне клиента, который называется «next/navigation». Это сильно отличается от «следующий/маршрутизатор». Кроме того, при использовании элементов «next/link» NextJS не запускаетonRouteChangeCompleteсобытие, когдаlocation.hashменяется, ноlocation.pathnameне.

Итак, чтобы обнаружить изменение хеша и прокрутить до связанного элемента, мне, наконец, пришлось реализовать этот хак:

      "use client"
import { Inter } from '@next/font/google'
import paragraph from './paragraph'
import Link from 'next/link'
import { useEffect, useState } from 'react'

const inter = Inter({ subsets: ['latin'] })

export default function Home() {
  const [navClick, setNavClick] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      const hash = window.location.hash;
      if (hash) document.querySelector(hash).scrollIntoView();
    }, 0);
  }, [navClick])

  const toggleNavClick = () => setNavClick((oldVal) => !oldVal);

  return (
    <main>
      <nav>
        <ul>
          <li>
            <Link href="/#one" onClick={toggleNavClick}>Section One</Link>
          </li>
          <li>
            <Link href="/#two" onClick={toggleNavClick}>Section Two</Link>
          </li>
          <li>
            <Link href="/#three" onClick={toggleNavClick}>Section Three</Link>
          </li>
        </ul>
      </nav>
      <div className="container">
        <section id="one">
          <h1>Section One</h1>
          <div dangerouslySetInnerHTML={{ __html: paragraph }} />
        </section>
        <section id="two">
          <h1>Section Two</h1>
          <div dangerouslySetInnerHTML={{ __html: paragraph }} />
        </section>
        <section id="three">
          <h1>Section Three</h1>
          <div dangerouslySetInnerHTML={{ __html: paragraph }} />
        </section>
      </div>
    </main>
  )
}

Поскольку изменение хэша не может быть обнаружено, поскольку событие не запускается, я в основном создал событие, переключивnavClickпри каждом переходе по ссылке. Логика навигации заключена вsetTimeout()функция, потому что она срабатывает послеwindow.locationобновляется.

Репозиторий: https://github.com/designly1/next-hash-test Демо: https://next-hash-test.vercel.app/

Мой обходной путь — не использовать компонент Link:

      <a href="#faqs">FAQS</a>

Мое решение для прокрутки к конкретному заголовку таково.

        const scrollToHeader = (anchorId: string) => {
    const headerElement = document.getElementById(anchorId);
    if (headerElement) {
      const offset = 100;
      const scrollPosition = headerElement.getBoundingClientRect().top + window.scrollY - offset;
  
      window.scrollTo({
        top: scrollPosition,
        behavior: "smooth",
      });
    }
  };
      <Link
            key={headerId}
            className="text-sm font-semibold text-primary hover:underline"
            href={`#${headerId}`}
            scroll={false}
            onClick={(e) => {
              scrollToHeader(headerId);
              onLinkClick?.();
            }}>
            {parser(String(formattedHeaderText))}
</Link>
Другие вопросы по тегам