Загрузка меню
Меню кафе меняется по сезонам, поэтому ему не место в коде. Оно лежит в файле menu.json, и приложение его загружает — так же, как в курсе по JavaScript вы загружали файлы через fetch(). В компоненте для этого есть место — 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>Вот что происходит:
- Vue создаёт компонент:
menu— пустой массив. - Vue монтирует его: страница показывает компонент с пустым списком, и Vue вызывает функцию, переданную в
onMounted. Она запрашиваетmenu.jsonи ждёт. - Ответ приходит через мгновение.
menu.value = …кладёт меню в реф, и Vue обновляет страницу, как после любого другого изменения состояния.
Функция объявлена как async, поэтому в ней можно использовать await, как в функциях, которые загружали данные в курсе по JavaScript. Слово async ставится перед скобками стрелочной функции.
Почему бы не написать две строки с await прямо в начале <script setup>, вместе с остальным кодом? Так это упражнение и начинается, и страница ничего не показывает, даже заголовок. Консоль сообщает:
[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>await в начале заставляет ждать весь компонент: Vue не может закончить его создание, пока нет данных, и показывает такой компонент только внутри <Suspense> — части Vue, которая всё ещё экспериментальная и которой в этом курсе мы не пользуемся. Поэтому никогда не ставьте await в начало <script setup>. Загружайте данные в onMounted, а пока пусть страница покажет что-нибудь другое.
Например, Загрузка…: при медленном соединении данные могут идти несколько секунд. Реф, который равен true, пока данных нет, подсказывает шаблону, что показывать.
Задание
- 1
Загрузите меню в
onMounted: импортируйте его рядом сrefи перенесите две строки сawaitвonMounted(async () => { … });. Страница покажет заголовок, а через мгновение — меню. - 2
Пока меню загружается, показывайте
<p>Загрузка…</p>вместо списка. Добавьте рефloading, который сначала равенtrue, после получения меню сделайте егоfalseвonMounted, а абзац показывайте черезv-if="loading", список — черезv-else.