Une boîte renversée de blocs LEGO

Mise en garde avec la déstructuration des props Vue

La déstructuration d’objets en JavaScript est une fonctionnalité très intéressante. L’utiliser avec Vue peut cependant prendre une tournure particulière… Nous allons nous pencher sur une mise en garde à ce sujet.

Le problème

Je vais expliquer mon cas d’utilisation. Un composant PostList sur une application de forum avait besoin d’être utilisé selon deux scénarios :

  • l’un avait besoin que les messages soient classés dans l’ordre croissant,
  • l’autre avait besoin du contraire.

En travaillant sur ce composant, j’ai déclaré mes props de cette façon :

1
2
3
4
5
6
7
interface PostListProps {
  posts: Post[];
  orderBy: OrderByDirection;
}
const { posts, orderBy } = withDefaults(defineProps<PostListProps>(), {
  orderBy: OrderByDirection.Asc,
});

Ensuite, j’ai utilisé une computed pour ordonner les posts selon les besoins :

1
2
3
4
5
6
7
8
const orderedPosts = computed(() => {
  if (orderBy === OrderByDirection.Asc) {
    return posts;
  }
  return [...posts].sort((first, next) =>
    first.publishedAt! < next.publishedAt! ? 1 : -1
  );
});

Lorsque j’ai testé ce code, l’ajout d’un nouveau message a fonctionné, mais il ne s’est pas affiché dans la liste.

En utilisant Vue DevTools, j’ai vu l’état de Pinia se mettre à jour et le composant parent du composant PostList a bien fourni la liste complète…

La raison et solution

Pourquoi le nouveau message n’apparaîssait-il pas ?

La déstructuration de l’objet props avait brisé la réactivité et computed nécessite une dépendance réactive pour se mettre à jour !

Le code est donc devenu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const props = withDefaults(defineProps<PostListProps>(), {
  orderBy: OrderByDirection.Asc,
});
const orderedPosts = computed(() => {
  if (props.orderBy === OrderByDirection.Asc) {
    return props.posts;
  }
  return [...props.posts].sort((first, next) =>
    first.publishedAt! < next.publishedAt! ? 1 : -1
  );
});

Utilisation de toRefs

Si vous insistez à déstructurer vos props, assurez-vous de les rendre réactives.

Pour cela, Vue fournit un utilitaire pour l’occasion :toRefs .

Le code se présente comme suit :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import { toRefs } from "vue";

const props = withDefaults(defineProps<PostListProps>(), {
  orderBy: OrderByDirection.Asc,
});

// `posts` et `orderBy` sont maintenant réactives.
const { posts, orderBy } = toRefs(props);

const orderedPosts = computed(() => {
  if (orderBy === OrderByDirection.Asc) {
    return posts;
  }
  return [...posts].sort((first, next) =>
    first.publishedAt! < next.publishedAt! ? 1 : -1
  );
});

La déstructuration se révèle très utile, mais avec Vue, il faut l’utiliser avec précaution, en particulier si vous utilisez des computed 🙂. Merci, toRefs!

Crédit : Photo de Scott McNiel sur Pexels.