Loading the Menu
The café's menu changes with the seasons, so it doesn't belong in the code. It's in a file, menu.json, and the app loads it, as you loaded files with fetch() in the JavaScript course. In a component, the place for that is onMounted:
<script setup>
import { onMounted, ref } from "vue";
const menu = ref([]);
onMounted(async () => {
const response = await fetch("menu.json");
menu.value = await response.json();
});
</script>Here's what happens:
- Vue creates the component:
menuis an empty array. - Vue mounts it: the page shows the component, with an empty list, and Vue calls the function given to
onMounted. It asks formenu.jsonand waits. - The answer comes a moment later.
menu.value = …puts the menu into the ref, and Vue updates the page, as after any other change of state.
The function is async, so it can use await, as the functions that loaded data in the JavaScript course did. async goes before the parentheses of the arrow function.
Why not write the two lines with await right at the top of <script setup>, with the rest of the code? This exercise starts that way, and the page shows nothing, not even the heading. The console says:
[Vue warn]: Component <App>: setup function returned a promise, but no <Suspense> boundary was found in the parent component tree. A component with async setup() must be nested in a <Suspense> in order to be rendered.
at <App>An await at the top makes the whole component wait: Vue can't finish creating it until the data is there, and it shows such a component only inside <Suspense>, a part of Vue that's still experimental and that this course doesn't use. So never put await at the top of <script setup>. Load data in onMounted, and let the page show something in the meantime.
Such as Loading…: on a slow connection, the data can take a few seconds to arrive. A ref that's true until the data is there tells the template what to show.
Instructions
- 1
Load the menu in
onMounted: import it next toref, and move the two lines withawaitintoonMounted(async () => { … });. The page shows the heading, and a moment later the menu. - 2
While the menu is loading, show
<p>Loading…</p>instead of the list. Add a refloadingthat starts astrue, set it tofalseinonMountedonce the menu is there, and show the paragraph withv-if="loading"and the list withv-else.