Kurs Svelte i SvelteKit · Moduł 11: Routing w SvelteKit

Strony błędów i specjalne

2 min czytania ·
W tej lekcji4

+error.svelte

<!-- src/routes/+error.svelte -->
<script>
  import { page } from '$app/state';
</script>

<h1>Błąd {page.status}</h1>
<p>{page.error?.message}</p>

<a href="/">Wróć na stronę główną</a>

Obiekt page z $app/state jest reaktywny i czytasz go bez znaku $. Dawny store $page z modułu $app/stores został w SvelteKit 3 usunięty.

Zgłaszanie błędów

// src/routes/warriors/[id]/+page.js
import { error } from '@sveltejs/kit';

export function load({ params }) {
  const warrior = getWarrior(params.id);

  if (!warrior) {
    error(404, 'Wojownik nie znaleziony');
  }

  return { warrior };
}

Funkcja error() sama rzuca wyjątek, więc nie piszesz przed nią throw (to zapis ze SvelteKit 1). Drugim argumentem jest zawsze tekst komunikatu.

+page.js vs +page.server.js

// +page.js - działa na serwerze I kliencie
export function load({ params, fetch }) {
  // Może być wywołane podczas nawigacji client-side
  return { data };
}
// +page.server.js - TYLKO serwer
export function load({ params, locals }) {
  // Dostęp do bazy danych, sekretów, itp.
  return { data };
}

Przekierowania

import { redirect } from '@sveltejs/kit';

export function load({ locals }) {
  if (!locals.user) {
    redirect(303, '/login');
  }

  return { user: locals.user };
}

Tak samo jak error(), funkcja redirect() rzuca wyjątek sama - bez throw.

Kod do tej lekcji: App.svelte
<script>
  // Nawigacja programowa i loading states

  let loading = $state(false);
  let currentPage = $state('home');

  async function navigateTo(page) {
    loading = true;

    // Symulacja ładowania danych
    await new Promise(r => setTimeout(r, 1000));

    currentPage = page;
    loading = false;
  }

  // Symulacja beforeNavigate
  function handleBeforeNavigate(e, page) {
    if (currentPage === 'form' && !confirm('Opuścić stronę?')) {
      e.preventDefault();
      return;
    }
    navigateTo(page);
  }
</script>

<main class="navigation-demo">
  <h1>Nawigacja SvelteKit</h1>

  <nav class="nav">
    <button onclick={(e) => handleBeforeNavigate(e, 'home')}>Home</button>
    <button onclick={(e) => handleBeforeNavigate(e, 'warriors')}>Warriors</button>
    <button onclick={(e) => handleBeforeNavigate(e, 'form')}>Form</button>
  </nav>

  {#if loading}
    <div class="loading">
      <div class="spinner"></div>
      <p>Ładowanie...</p>
    </div>
  {:else}
    <section class="content">
      {#if currentPage === 'home'}
        <h2>Strona główna</h2>
        <p>Witaj w aplikacji!</p>
      {:else if currentPage === 'warriors'}
        <h2>Wojownicy</h2>
        <p>Lista załadowana z serwera</p>
      {:else if currentPage === 'form'}
        <h2>Formularz</h2>
        <p>Opuszczenie spowoduje utratę danych!</p>
        <input placeholder="Wpisz coś..." />
      {/if}
    </section>
  {/if}

  <section class="code-example">
    <h2>Programmatic navigation</h2>
    <pre>
import {"{"} goto {"}"} from '$app/navigation';

// Prosta nawigacja
goto('/warriors');

// Z opcjami
goto('/warriors', {"{"}
  replace: true,
  refreshAll: true
{"}"});
    </pre>
  </section>
</main>

<style>
  .navigation-demo {
    font-family: 'Georgia', serif;
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
    background: #0a1628;
    color: #b8d4f7;
    min-height: 100vh;
  }

  h1 {
    color: #4a90d9;
    text-align: center;
  }

  .nav {
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    margin-bottom: 2rem;
  }

  button {
    padding: 0.75rem 1.5rem;
    background: #1e3a5f;
    color: #b8d4f7;
    border: 1px solid #4a90d9;
    border-radius: 4px;
    cursor: pointer;
  }

  button:hover {
    background: #2a4a6f;
  }

  .loading {
    text-align: center;
    padding: 3rem;
  }

  .spinner {
    width: 50px;
    height: 50px;
    border: 4px solid #1e3a5f;
    border-top-color: #4a90d9;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin: 0 auto 1rem;
  }

  @keyframes spin {
    to { transform: rotate(360deg); }
  }

  section {
    background: rgba(74, 144, 217, 0.1);
    border: 1px solid #4a90d9;
    border-radius: 8px;
    padding: 1rem;
    margin: 1rem 0;
  }

  h2 {
    color: #4a90d9;
    margin-top: 0;
  }

  input {
    width: 100%;
    padding: 0.75rem;
    background: rgba(0,0,0,0.3);
    border: 1px solid #4a90d9;
    border-radius: 4px;
    color: #b8d4f7;
    margin-top: 0.5rem;
  }

  pre {
    background: rgba(0,0,0,0.5);
    padding: 1rem;
    border-radius: 4px;
    font-size: 0.85rem;
    overflow-x: auto;
  }
</style>

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak zgłosić błąd 404 w funkcji load (SvelteKit 3)?

Przydatne artykuły