Mise en garde sur 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 :
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 :
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 :
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 :
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
!