The problem
I will explain my use case: I had a PostList
component on a forum application. I used this component is two places:
- one needed the posts to be ordered in the ascending order,
- the other needed the contrary.
While working on that, I declared my props this way:
1
2
3
4
5
6
7
8
|
interface PostListProps {
posts: Post[];
orderBy: OrderByDirection;
}
const { posts, orderBy } = withDefaults(defineProps<PostListProps>(), {
orderBy: OrderByDirection.Asc,
});
|
Then, I used a computed to order the posts as needed:
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
);
});
|
When I went to test this code, adding a new post worked but it didn’t show in the list.
Using Vue DevTools, I saw the Pinia state updating and the parent component of PostList
component did provide the full list…
The reason and solution
Why didn’t the new post appear?
Destructuring the props object broke the reactivity and computed
requires a reactive dependency!
So the valid code became:
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
);
});
|
Using toRefs
If you insist to destructure the props, make sure to reactive them.
For that, Vue provides a nice utility: toRefs
.
The code would like that:
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` and `orderBy` are now reactive.
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
);
});
|
Conclusion
Destructuring is great, but with Vue, use it carefully, especially with computed
🙂. Thank you, toRefs
!
Credit: Photo by Scott McNiel on Pexels.