Favorites That Stay

In Computed Values and Watchers, you saved the order in localStorage with watch, and read it back when the app started. The app in this exercise lets the customer star their favorite items, and its watch saves them already. What's missing is reading them, in the same way, right when the ref is created:

const saved = localStorage.getItem("favorites");
const favorites = ref(saved === null ? [] : JSON.parse(saved));

As before, null from getItem() means that nothing has been saved yet, and the customer starts with an empty array.

But this app also loads its menu, in onMounted. Why not read the favorites there too? Because localStorage answers at once, while fetch() has to wait for the server. There's no reason to wait, so read it at the top of <script setup>: when Vue shows the page for the first time, the stars are already right.

When this app starts, its data comes from three places, at three moments:

  • what's saved in the browser: at once, when the component is created,
  • the file menu.json: a moment after the component is mounted,
  • the customer: whenever they click.

A computed value made from data from two places is right at every moment. The names of the favorite items, made from menu and favorites, are empty at first, although the ids are already there, and appear when the menu arrives, without any extra code.

Typical mistakes:

  • JSON.parse() without the check for null: JSON.parse(null) gives null, and when the template reads favorites.includes(…), the page ends with TypeError: Cannot read properties of null (reading 'includes'). It works for you, because you've saved something, and fails for every new customer.
  • Saving before reading: if the ref starts as [] and a watch with { immediate: true } saves it at once, the saved favorites are replaced with an empty array before anything has read them.

Instructions

  1. When the app starts, read the saved favorites, and start favorites with them. Try it: star two items and click Run. The stars stay.

  2. Under the heading, show the names of the favorite items: Your favorites: Cappuccino, Carrot Cake. Make them a computed value from menu and favorites, with filter(), map() and join(", "), and show the paragraph only when there's at least one name.