Kurs Svelte i SvelteKit · Moduł 7: Cykl życia

Walhalla - Cykl życia komponentów

2 min czytania ·
W tej lekcji4

Witaj w Walhalli! Jak wojownicy przybywają i odchodzą z tych sal, tak komponenty mają swój cykl życia - od powstania do zniszczenia.

Lifecycle w Svelte

Komponent tworzony
       ↓
   onMount()     ← Zamontowany w DOM
       ↓
   [życie]       ← $effect.pre / $effect przy zmianach stanu
       ↓
  onDestroy()    ← Usuwany z DOM

W Svelte 5 nie ma hooków uruchamianych przy każdej aktualizacji całego komponentu. Zamiast nich efekty ($effect.pre, $effect) reagują tylko na stan, którego używają - poznasz je dokładniej w następnej lekcji.

onMount - Przybycie do Walhalli

<script>
  import { onMount } from 'svelte';

  let data = $state(null);

  onMount(() => {
    console.log('Komponent zamontowany!');

    // Fetch danych
    fetch('/api/warriors')
      .then(r => r.json())
      .then(d => data = d);

    // Cleanup (opcjonalny)
    return () => {
      console.log('Komponent będzie odmontowany');
    };
  });
</script>

onDestroy - Odejście na Ragnarök

<script>
  import { onDestroy } from 'svelte';

  const interval = setInterval(() => {
    console.log('tick');
  }, 1000);

  onDestroy(() => {
    clearInterval(interval);
    console.log('Posprzątano!');
  });
</script>

Svelte 5: $effect z funkcją sprzątającą

$effect uruchamia się po zamontowaniu komponentu, a funkcja, którą zwraca, sprząta przy odmontowaniu. Efekt, który nie czyta żadnego stanu, działa raz - jak onMount i onDestroy w jednym:

<script>
  // Efekt nie czyta stanu, więc uruchomi się raz po zamontowaniu
  $effect(() => {
    console.log('Zamontowany!');

    const interval = setInterval(() => {
      console.log('tick');
    }, 1000);

    return () => {
      clearInterval(interval);
      console.log('Odmontowany!');
    };
  });
</script>

Gdy efekt czyta stan (np. count), uruchamia się ponownie po każdej jego zmianie, a przed każdym kolejnym uruchomieniem wywołuje swoją funkcję sprzątającą. Do kodu, który ma zadziałać dokładnie raz, onMount nadal jest dobrym wyborem.

Życie w Walhalli ma swój rytm - tak jak lifecycle komponentów!

Kod do tej lekcji: App.svelte
<script>
  // Walhalla - Cykl życia komponentów
  // onMount, onDestroy i $effect z funkcją sprzątającą
  import { onMount, untrack } from 'svelte';
  import Einherjar from './Einherjar.svelte';

  let mounted = $state(false);
  let showWarrior = $state(true);
  let logs = $state([]);

  // untrack: log można wywołać nawet z efektu, a zapis do logs
  // nie stanie się jego zależnością (więcej w lekcji 7_2)
  function log(message) {
    untrack(() => {
      logs = [...logs, { time: new Date().toLocaleTimeString(), message }].slice(-8);
    });
  }

  onMount(() => {
    mounted = true;
    log('onMount (App) - Walhalla otwiera wrota');
  });
</script>

<main class="lifecycle">
  <h1>Walhalla - Cykl Życia</h1>
  <p class="subtitle">onMount, onDestroy, $effect</p>

  <section>
    <h2>Status</h2>
    <p>App zamontowany: <strong>{mounted ? 'Tak' : 'Nie'}</strong></p>
    <button onclick={() => (showWarrior = !showWarrior)}>
      {showWarrior ? 'Wyślij wojownika na Ragnarök' : 'Przywołaj wojownika'}
    </button>
  </section>

  {#if showWarrior}
    <Einherjar onLog={log} />
  {:else}
    <p class="empty">Wojownik odszedł. Przywołaj go, aby znów zobaczyć onMount.</p>
  {/if}

  <section class="logs">
    <h2>Logi cyklu życia</h2>
    {#each logs as entry}
      <p><span class="time">{entry.time}</span> {entry.message}</p>
    {/each}
  </section>
</main>

<style>
  .lifecycle {
    font-family: 'Georgia', serif;
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
    background: linear-gradient(135deg, #1a0a0a 0%, #2a1a0a 100%);
    color: #e8d5b7;
    min-height: 100vh;
  }

  h1 {
    color: #ffd700;
    text-align: center;
  }

  .subtitle {
    text-align: center;
    color: #8b7355;
  }

  section {
    background: rgba(212, 175, 55, 0.1);
    border: 1px solid #d4af37;
    border-radius: 8px;
    padding: 1rem;
    margin: 1rem 0;
  }

  h2 {
    color: #d4af37;
    font-size: 1rem;
    margin-top: 0;
  }

  strong {
    color: #ffd700;
  }

  button {
    padding: 0.5rem 1rem;
    background: #3d2914;
    color: #e8d5b7;
    border: 1px solid #d4af37;
    border-radius: 4px;
    cursor: pointer;
  }

  .empty {
    color: #8b7355;
    font-style: italic;
  }

  .logs {
    max-height: 250px;
    overflow-y: auto;
  }

  .logs p {
    margin: 0.25rem 0;
    padding: 0.25rem 0.5rem;
    background: rgba(0,0,0,0.3);
    border-radius: 4px;
    font-size: 0.9rem;
  }

  .time {
    color: #8b7355;
    font-family: monospace;
    margin-right: 0.5rem;
  }
</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. Kiedy wywoływana jest funkcja onMount?

  2. 2. Jak wykonać cleanup w onMount?

Przydatne artykuły