Skip to main content
Bases de Svelte
Introduction
Réactivité
Props
Logique
Évènements
Liaisons
Classes et styles
Actions
Transitions
Svelte avancé
Réactivité avancée
Réutiliser du contenu
Mouvements
Liaisons avancées
Transitions avancées
API de contexte
Éléments spéciaux
<script module>
Next steps
Bases de SvelteKit
Introduction
Routing
Chargement de données
En-têtes et cookies
Modules partagés
Formulaires
Routes d’API
$app/state
Erreurs et redirections
SvelteKit avancé
Hooks
Options de page
Options de lien
Routing avancé
Chargement avancé
Variables d’environnement
Conclusion

Avec use:enhance, nous pouvons aller plus loin que simplement nous contenter d’émuler le comportement natif du navigateur. En fournissant un callback, nous pouvons ajouter des choses comme des états d’attente et des interfaces optimistes. Simulons un réseau dégradé en ajoutant un retard artificiel sur nos deux actions :

src/routes/+page.server
export const actions = {
	create: async ({ cookies, request }) => {
		await new Promise((fulfil) => setTimeout(fulfil, 1000));
		...
	},

	delete: async ({ cookies, request }) => {
		await new Promise((fulfil) => setTimeout(fulfil, 1000));
		...
	}
};

Lorsque nous créons ou supprimons des tâches, cela prend maintenant une seconde complète avant que l’interface ne se mette à jour, laissant l’utilisateur ou l’utilisatrice le temps de se demander si quelque chose ne va pas. Pour résoudre cela, ajoutons un état local...

src/routes/+page
<script>
	import { fly, slide } from 'svelte/transition';
	import { enhance } from '$app/forms';

	let { data, form } = $props();

	let creating = $state(false);
	let deleting = $state([]);
</script>
<script lang="ts">
	import { fly, slide } from 'svelte/transition';
	import { enhance } from '$app/forms';

	let { data, form } = $props();

	let creating = $state(false);
	let deleting = $state([]);
</script>

... et activons creating dans le premier use:enhance :

src/routes/+page
<form
	method="POST"
	action="?/create"
	use:enhance={() => {
		creating = true;

		return async ({ update }) => {
			await update();
			creating = false;
		};
	}}
>
	<label>
		ajouter une tâche :
		<input
			disabled={creating}
			name="description"
			value={form?.description ?? ''}
			autocomplete="off"
			required
		/>
	</label>
</form>

Nous pouvons alors afficher un message pendant que les données sont enregistrées :

src/routes/+page
<ul class="todos">
	<!-- ... -->
</ul>

{#if creating}
	<span class="saving">sauvegarde en cours...</span>
{/if}

Pour ce qui est des suppressions, nous n’avons pas vraiment besoin d’attendre que le serveur valide quelque chose — nous pouvons juste mettre à jour l’interface immédiatement :

src/routes/+page
<ul class="todos">
	{#each data.todos.filter((todo) => !deleting.includes(todo.id)) as todo (todo.id)}
		<li in:fly={{ y: 20 }} out:slide>
			<form
				method="POST"
				action="?/delete"
				use:enhance={() => {
					deleting = [...deleting, todo.id];
					return async ({ update }) => {
						await update();
						deleting = deleting.filter((id) => id !== todo.id);
					};
				}}
			>
				<input type="hidden" name="id" value={todo.id} />
				<button aria-label="Marquer comme fait">✔</button>

				{todo.description}
			</form>
		</li>
	{/each}
</ul>

use:enhance est très personnalisable — vous pouvez annuler des soumissions avec cancel(), gérer les redirections, contrôler la réinitialisation du formulaire, parmi d’autres. Voir la documentation pour plus de détails.

Modifier cette page sur Github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<script>
	import { fly, slide } from 'svelte/transition';
	import { enhance } from '$app/forms';
 
	let { data, form } = $props();
</script>
 
<div class="centered">
	<h1>à faire</h1>
 
	{#if form?.error}
		<p class="error">{form.error}</p>
	{/if}
 
	<form method="POST" action="?/create" use:enhance>
		<label>
			ajouter une tâche :
			<input
				name="description"
				value={form?.description ?? ''}
				autocomplete="off"
				required
			/>
		</label>
	</form>
 
	<ul class="todos">
		{#each data.todos as todo (todo.id)}
			<li in:fly={{ y: 20 }} out:slide>
				<form method="POST" action="?/delete" use:enhance>
					<input type="hidden" name="id" value={todo.id} />
					<span>{todo.description}</span>
					<button aria-label="Marquer comme fait"></button>
				</form>
			</li>
		{/each}
	</ul>
</div>
 
<style>
	.centered {
		max-width: 20em;
		margin: 0 auto;
	}
 
	label {
		width: 100%;
	}
 
	input {
		flex: 1;
	}
 
	span {
		flex: 1;
	}
 
	button {
		border: none;
		background: url(./remove.svg) no-repeat 50% 50%;
		background-size: 1rem 1rem;
		cursor: pointer;
		height: 100%;
		aspect-ratio: 1;
		opacity: 0.5;
		transition: opacity 0.2s;
	}
 
	button:hover {
		opacity: 1;
	}
 
	.saving {
		opacity: 0.5;
	}
</style>