Вопрос или проблема
Я работаю над проектом на Vue 3, используя Composition API с TypeScript, и сталкиваюсь с проблемой, связанной с горячей заменой модулей (HMR) в Vite.
Описание проблемы:
Родительский компонент:
У меня есть переменная ref под названием data в родительском компоненте. Я передаю эти данные в дочерний компонент, используя двустороннюю привязку через v-model:data=”data”. В шаблоне родительского компонента у меня есть цикл v-for, который создает иконки для каждого элемента в data.
ParentComponent.vue:
<template>
<ChildComponent v-model:data="data" />
<div v-for="item in data" :key="item.id">
<!-- Отображение иконки для каждого элемента -->
<v-icon>mdi-blank-circle</icon>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
import Icon from './Icon.vue';
const data = ref([]);
</script>
Дочерний компонент: В дочернем компоненте я использую defineModel для определения модели данных. У меня есть асинхронная функция fetchData, которая получает данные и присваивает их data.value. Я вызываю onMounted(fetchData()), чтобы получить данные, когда компонент монтируется.
ChildComponent.vue:
<script setup lang="ts">
import { defineModel, onMounted } from 'vue';
import { getMyData } from './api';
const data = defineModel('data');
const fetchData = async () => {
data.value = await getMyData();
};
onMounted(fetchData());
</script>
Каждый раз, когда Vite выполняет горячую перезагрузку в коде дочернего компонента (например, добавляя некоторые console.log в код), дочерний компонент повторно получает данные. Это повторное получение обновляет данные родителя, вызывая дублирование записей. В результате иконки в цикле v-for родительского компонента дублируются.
Проблема в том, что родительский компонент не перерисовывается, только дочерний компонент перерисовывается, и это вызывает следующее получение данных fetchData, и двусторонняя привязка обновляет значение в родительском компоненте с следующими данными. Например: 1. первое загрузка представления: 4 иконки 2. некоторые изменения в дочернем компоненте: 8 иконок И так далее… Когда я использую кнопку перезагрузки в браузере, все работает правильно, и у меня отображается 4 иконки.
-
Как я могу предотвратить повторное получение данных дочерним компонентом и вызвать дубликаты в родительском компоненте, когда происходит горячая перезагрузка Vite?
-
Существует ли рекомендуемый паттерн или лучшие практики в Vue 3 с Composition API и Vite для обработки этой ситуации?
Любая информация или предложения будут очень признательны!
Ответ или решение
Устранение проблемы повторного извлечения данных при горячей замене модулей в Vue 3 с использованием Vite
В рамках вашего проекта на Vue 3 с использованием Composition API и TypeScript вы столкнулись с проблемой, когда горячая замена модулей (HMR) в Vite вызывает повторное извлечение данных в дочернем компоненте. Это, в свою очередь, приводит к дублированию иконок в родительском компоненте, поскольку данные обновляются каждый раз, когда ребенок обновляется. Давайте разберем, как можно решить эту проблему и какие лучшие практики использовать для предотвращения подобных ситуаций в будущем.
Проблема описания
-
Структура компонента:
- В родительском компоненте у вас есть переменная
data
, которая передается в дочерний компонент через двустороннее связываниеv-model
. - Дочерний компонент выполняет асинхронную функцию
fetchData
, которая получает данные и присваивает ихdata.value
при монтировании компонента.
- В родительском компоненте у вас есть переменная
-
Симптомы проблемы:
- При каждом изменении в дочернем компоненте, связанном с HMR, функция
fetchData
срабатывает, что приводит к повторной загрузке данных и удвоению значений в родительском компоненте.
- При каждом изменении в дочернем компоненте, связанном с HMR, функция
Решение проблемы
Чтобы избежать повторной выборки данных и дублирования значений в родительском компоненте при использовании горячей замены модулей, вы можете использовать следующие подходы:
-
Избегайте вызова
fetchData
без условий:
Вместо того, чтобы вызыватьfetchData
непосредственно вonMounted
, установите флаг, который будет отслеживать, загружались ли данные уже:<script setup lang="ts"> import { defineModel, onMounted } from 'vue'; import { getMyData } from './api'; const data = defineModel('data'); // Добавим флаг загрузки let isDataFetched = false; const fetchData = async () => { if (!isDataFetched) { data.value = await getMyData(); isDataFetched = true; // Установим флаг, чтобы данные не загружались повторно } }; onMounted(fetchData); </script>
-
Используйте
v-if
для условного рендеринга:
Добавьте условный рендеринг в родительском компоненте, чтобы отслеживать, была ли загружена информация, и предотвращать рендеринг дубликатов:<template> <ChildComponent v-model:data="data" /> <div v-if="data.length"> <div v-for="item in data" :key="item.id"> <v-icon>mdi-blank-circle</v-icon> </div> </div> </template>
-
Отказ от двустороннего связывания при HMR:
Рассмотрите возможность использования однонаправленного потока данных. Вместо использованияv-model
, можно просто передать данные в дочерний компонент как:data="data"
, а изменения отправлять через события. Это может снизить вероятность возникновения проблем при HMR. -
Оптимизация HMR:
Если вы продолжаете сталкиваться с явлениями HMR, попробуйте отключить HMR для определенных частей вашего приложения во время разработки, чтобы изучить взаимодействие компонентов более детально и понять, в чем происходит проблема.
Лучшие практики
- Четкое разделение данных и представления: Убедитесь, что ваш компонент получает только необходимые данные и обрабатывает их минимально.
- Управление состоянием: Для более комплексных приложений рассмотрите использование библиотек управления состоянием, таких как Vuex или Pinia, которые помогут избежать проблем с дублированием данных и сложностью передачи их между компонентами.
- Тестирование в режиме разработки: Регулярно тестируйте вашу логику в режиме разработки, чтобы убедиться, что изменения в компонентах не влияют на результаты работы.
Заключение
Решение проблемы повторного извлечения данных в вашем проекте на Vue 3 с использованием Vite возможно через правильную организацию кода и использование флагов состояния. Надеюсь, что предложенные подходы и практические советы помогут вам эффективно справляться с данной проблемой и улучшить архитектуру вашего приложения.