Kurs Svelte i SvelteKit · Moduł 4: Props i zdarzenia

Context API

3 min czytania ·
W tej lekcji5

Dla głęboko zagnieżdżonych komponentów, Context API pozwala uniknąć "prop drilling".

Problem: Prop drilling

App
└── Layout
    └── Sidebar
        └── Navigation
            └── NavItem  <-- potrzebuje danych z App!

Przekazywanie props przez każdy poziom jest uciążliwe.

Rozwiązanie: Context

<!-- App.svelte -->
<script>
  import { setContext } from 'svelte';
  import Layout from './Layout.svelte';

  const user = $state({
    name: 'Ragnar',
    role: 'jarl',
    gold: 1000
  });

  // Ustaw kontekst - dostępny dla wszystkich potomków
  setContext('user', user);
</script>

<Layout />
<button onclick={() => user.gold += 100}>+100 złota</button>
<!-- NavItem.svelte (głęboko zagnieżdżony) -->
<script>
  import { getContext } from 'svelte';

  // Pobierz kontekst - działa na dowolnym poziomie!
  const user = getContext('user');
</script>

<div class="nav-item">
  <span>{user.name}</span>
  <span>({user.role}, {user.gold} złota)</span>
</div>

Do kontekstu trafia obiekt $state, więc potomkowie widzą jego zmiany. Zmieniaj jego pola (user.gold += 100) zamiast przypisywać nowy obiekt - inaczej potomkowie zostaną ze starym.

Typowany Context

Klucze kontekstu i funkcje do nich warto trzymać w jednym pliku. Od Svelte 5.40 robi to za Ciebie createContext - zwraca parę funkcji, bez ręcznego klucza:

// context.ts
import { createContext } from 'svelte';

interface User {
  name: string;
  role: string;
}

export const [getUserContext, setUserContext] = createContext<User>();

W starszych wersjach Svelte 5 to samo zapiszesz przez setContext i getContext z unikalnym kluczem:

// context.js
import { getContext, setContext } from 'svelte';

const USER_KEY = Symbol('user');

export function setUserContext(user) {
  setContext(USER_KEY, user);
}

export function getUserContext() {
  return getContext(USER_KEY);
}
<!-- App.svelte -->
<script>
  import { setUserContext } from './context.js';

  const user = $state({ name: 'Ragnar', role: 'jarl' });
  setUserContext(user);
</script>
<!-- DeepChild.svelte -->
<script>
  import { getUserContext } from './context.js';

  const user = getUserContext();
</script>

<p>{user.name}</p>

Context vs Props vs stan globalny

MetodaKiedy używać
PropsBezpośredni rodzic-dziecko
ContextGłęboka hierarchia, dane "per-tree"
Stan globalny$state w pliku .svelte.js albo stores (moduł 8), wiele drzew komponentów

Przykład: Theme Context

<!-- ThemeProvider.svelte -->
<script>
  import { setContext } from 'svelte';

  let { children } = $props();

  let theme = $state('dark');

  setContext('theme', {
    get current() { return theme; },
    toggle() { theme = theme === 'dark' ? 'light' : 'dark'; }
  });
</script>

<div class="theme-{theme}">
  {@render children()}
</div>
<!-- ThemedButton.svelte -->
<script>
  import { getContext } from 'svelte';

  const theme = getContext('theme');
</script>

<button class={theme.current} onclick={theme.toggle}>
  Zmień motyw ({theme.current})
</button>

Getter current zawsze zwraca aktualną wartość theme, więc przycisk odświeża się po każdej zmianie motywu.

Context to tajne przejścia w pałacu Asgardu - dane płyną bez przeszkód!

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 używać Context API zamiast props?

  2. 2. Jakie funkcje z pakietu svelte ustawiają i pobierają kontekst po kluczu?

Zadania praktyczne w grze

  • Klikanie w kolejności

    Kiedy używać: props (bezpośrednia), context (głęboka), stan globalny (stores lub .svelte.js)

Przydatne artykuły