Powrót do strony głównej

Nawigacja po kotwicach w Next.js z useAnchorObserver

Artykuł opisuje implementację nawigacji po kotwicach w jednostronicowej aplikacji na Next.js z użyciem hooka useAnchorObserver. Automatyzowana jest synchronizacja przewijania i URL, obsługa historii przeglądarki i SEO. Podany jest pełny kod z ustawieniami.

Jednostronicówka na Next.js: nawigacja kotwicowa bez błędów
Advertisement 728x90

Nawigacja kotwicami w aplikacji jednostronicowej Next.js

W aplikacjach jednostronicowych Next.js nawigacja kotwicami umożliwia przechodzenie między sekcjami bez przeładowania strony. Hook useAnchorObserver z biblioteki react-use-observer-hooks automatyzuje synchronizację przewijania i URL: wykrywa widoczną sekcję podczas przewijania i przewija do kotwicy przy zmianie adresu.

Mechanizm działa dwukierunkowo: przewijanie aktualizuje URL przez IntersectionObserver, a zmiana URL (kliknięcie lub przycisk „wstecz”) inicjuje przewijanie do sekcji. Eliminuje to pętle sprzężenia zwrotnego i zapewnia poprawną obsługę historii przeglądarki.

Przygotowanie projektu

Użyj Next.js 15 z Pages Router, React 19 i Tailwind CSS v4. Zainstaluj zależność:

Google AdInline article slot
npm install react-use-observer-hooks

Wyłącz wbudowane przywracanie przewijania w next.config.ts, aby uniknąć konfliktu z hookiem:

const nextConfig = {
  experimental: {
    scrollRestoration: false,
  },
};

Utwórz catch-all route [[...slug]].tsx do obsługi ścieżek /, /about, /contact na jednej stronie.

Główny kod strony

Zdefiniuj tablicę sekcji z href, label i komponentami:

Google AdInline article slot
import { useAnchorObserver } from 'react-use-observer-hooks';
import { useRouter } from 'next/router';

const SECTIONS = [
  { href: '/',        label: 'Strona główna',    Component: HomeSection },
  { href: '/about',   label: 'O nas',   Component: AboutSection },
  { href: '/contact', label: 'Dołącz do nas', Component: ContactSection },
];

export default function Page() {
  const router = useRouter();

  const { ref, focusedAnchor } = useAnchorObserver<HTMLDivElement>({
    anchors: SECTIONS.map(s => s.href),
    currentAnchor: router.asPath,
    onAnchorChange: (anchor) => {
      router.push(anchor, undefined, { scroll: false, shallow: true });
    },
  });

  return (
    <>
      <Navbar sections={SECTIONS} activeHref={focusedAnchor} />

      <div ref={ref}>
        {SECTIONS.map(({ href, Component }) => (
          <section key={href} style={{ minHeight: '100vh' }}>
            <Component />
          </section>
        ))}
      </div>
    </>
  );
}

Kluczowe aspekty:

  • ref jest stosowany do kontenera sekcji. Hook mapuje bezpośrednie dzieci według indeksu do tablicy anchors.
  • scroll: false w router.push zapobiega automatycznemu przewijaniu Next.js.
  • shallow: true optymalizuje nawigację bez ponownego renderowania serwera.

Komponent nawigacji

Navbar używa <Link> z tymi samymi opcjami:

import Link from 'next/link';

export const Navbar = ({ sections, activeHref }) => (
  <nav>
    {sections.map(({ href, label }) => (
      <Link
        key={href}
        href={href}
        scroll={false}
        shallow
        className={activeHref === href ? 'active' : ''}
      >
        {label}
      </Link>
    ))}
  </nav>
);

focusedAnchor automatycznie podświetla aktywny element w zależności od widocznej sekcji.

Google AdInline article slot

Zachowanie aplikacji

Uzyskana implementacja zapewnia:

  • Otwieranie bezpośredniego linku /about od razu w odpowiedniej sekcji.
  • Poprawną obsługę przycisku „wstecz” w przeglądarce.
  • Indeksowanie przez wyszukiwarki za pomocą unikalnych URL.
  • Synchronizację menu z widoczną treścią.

Co jest ważne

  • Hook useAnchorObserver w pełni automatyzuje dwukierunkową synchronizację przewijania i URL.
  • Wyłączenie scrollRestoration jest obowiązkowe, aby uniknąć konfliktów.
  • Catch-all route Pages Router nadaje się do nawigacji typu SPA.
  • shallow: true + scroll: false minimalizują ponowne renderowania.
  • Obsługa historii przeglądarki i SEO od razu.

— Editorial Team

Advertisement 728x90

Czytaj dalej