Cours Svelte et SvelteKit · Module 4: Props et événements

Context API

3 min de lecture ·
Dans cette leçon5

Pour des composants profondément imbriqués, la Context API permet d'éviter le « prop drilling ».

Problème : Le Prop Drilling

App
└── Layout
    └── Sidebar
        └── Navigation
            └── NavItem  <-- a besoin des données de App !

Transmettre les props à chaque niveau est fastidieux.

Solution : Context

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

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

  // Définit le context - disponible pour tous les descendants
  setContext('user', user);
</script>

<Layout />
<button onclick={() => user.gold += 100}>+100 pièces d'or</button>
<!-- NavItem.svelte (profondément imbriqué) -->
<script>
  import { getContext } from 'svelte';

  // Récupère le context - fonctionne à n'importe quel niveau !
  const user = getContext('user');
</script>

<div class="nav-item">
  <span>{user.name}</span>
  <span>({user.role}, {user.gold} pièces d'or)</span>
</div>

Le context contient un objet $state, donc les descendants voient ses changements. Modifie ses champs (user.gold += 100) au lieu d'assigner un nouvel objet, sinon les descendants gardent l'ancien.

Context typé

Mieux vaut garder les clés de context et leurs fonctions dans un seul fichier. Depuis Svelte 5.40, createContext s'en charge : il renvoie une paire de fonctions, sans clé à gérer :

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

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

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

Dans les versions plus anciennes de Svelte 5, tu écris la même chose avec setContext et getContext et une clé unique :

// 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 état global

MéthodeQuand l'utiliser
PropsParent-enfant direct
ContextHiérarchie profonde, données par arbre
État global$state dans un fichier .svelte.js ou stores (module 8), plusieurs arbres de composants

Exemple : Context de thème

<!-- 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}>
  Changer de thème ({theme.current})
</button>

Le getter current renvoie toujours la valeur actuelle de theme, donc le bouton se met à jour après chaque changement de thème.

Le Context est comme des passages secrets dans le palais d'Asgard : les données circulent sans obstacle !

Entrées de la documentation utilisées dans cette leçon

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Quand utiliser le Context API à la place des props ?

  2. 2. Quelles fonctions du paquet svelte définissent et récupèrent un contexte par clé ?

Tâches pratiques dans le jeu

  • Clique dans l'ordre

    Quand utiliser : props (directe), context (profonde), état global (stores ou .svelte.js)

Articles utiles