Aller au contenu principal

Optimistic UI

Lorsque l'on fait des mutations, actuellement l'UI met un peu de temps à se mettre à jour, car la page attend que les données aient été modifiées côté serveur pour rappeler les loaders pour se mettre à jour.

Nous allons ici utiliser la technique de l'optimistic UI pour rendre notre interface plus réactive. Cela consiste à simuler l'état optimal suite à une modification. Par exemple, pour l'ajout d'une track, cela consiste à directement faire apparaitre la track dans la playlist et à la retirer de la liste des tracks disponibles avant même la fin de la mutation côté serveur.

Exercice

Ajouter de l'optimistic UI sur l'ajout et la suppression d'une track.

Guide

💿 Récupérer les données en cours de soumission dans le composant

Remix expose un hook useNavigation qui nous retourne un objet navigation dans lequel nous allons pouvoir récupérer les données qui sont en cours de soumissions dans la propriété formData.

En savoir plus

Voir la section useNavigation dans la doc.

astuce

Nous pouvons réutiliser le schéma Zod FormDataRequestSchema pour avoir une donnée bien typé.

Voir une solution
app/routes/_layout.playlists.$id.(edit).tsx
export default function Playlists() {
//..
const navigation = useNavigation();
const formData = navigation.formData
? FormDataRequestSchema.parse(Object.fromEntries(navigation.formData))
: undefined;
//...
}

💿 Reconstruire les listes de tracks de la playlist et des tracks disponibles

Nous allons maintenant pouvoir reconstruire, en fonction de l'action et de la présence ou non de données en cours de soumissions, les 2 listes de tracks.

Voir une solution
app/routes/_layout.playlists.$id.(edit).tsx
export default function Playlists() {
const { playlist: serverPlaylist, availableTracks: serverAvailableTracks } =
useLoaderData<typeof loader>();
//...
const playlist = formData
? formData.action === "add"
? {
...serverPlaylist,
tracks: [
serverAvailableTracks.find(
(track) => track.id === formData.track_id
),
...serverPlaylist.tracks,
].filter(isNonUndefined),
}
: {
...serverPlaylist,
tracks: serverPlaylist.tracks.filter(
(track) => track.id !== formData.track_id
),
}
: serverPlaylist;

const availableTracks = formData
? formData.action === "add"
? serverAvailableTracks.filter((track) => track.id !== formData.track_id)
: [
serverPlaylist.tracks.find((track) => track.id === formData.track_id),
...serverAvailableTracks,
].filter(isNonUndefined)
: serverAvailableTracks;

//...
}
👏 Votre application est maintenant beaucoup plus réactive !

Voyons maintenant comment ajouter un peu de style spécifique à notre route.