Наблюдатели: watch и watchEffect
Наблюдатель — функция, которую Vue вызывает, когда меняются определённые данные. computed возвращает новое значение, а наблюдатель выполняет действие: сохраняет данные, отправляет запрос, пишет в консоль. Такие действия называют побочными эффектами.
Функция watch
Первый аргумент — что отслеживать, второй — что сделать при изменении:
<!-- src/App.vue -->
<script setup>
import { ref, watch } from 'vue'
const query = ref('')
watch(query, (newValue, oldValue) => {
console.log(`Поиск: было «${oldValue}», стало «${newValue}»`)
})
</script>
<template>
<input v-model="query" placeholder="Найти задачу">
</template>Наберите в поле «хл» — в консоли браузера появятся две строки: сначала Поиск: было «», стало «х», затем Поиск: было «х», стало «хл». Директива v-model связывает поле с переменной, подробно она разобрана в уроке про формы.
Сохранение задач
Типичная задача для watch — сохранить список в localStorage после каждого изменения:
<script setup>
import { ref, watch } from 'vue'
const saved = localStorage.getItem('todos')
const todos = ref(saved ? JSON.parse(saved) : [])
watch(todos, (value) => {
localStorage.setItem('todos', JSON.stringify(value))
}, { deep: true })
</script>После перезагрузки страницы задачи остаются на месте. Опция deep: true нужна, чтобы наблюдатель срабатывал и при изменении полей внутри задач, например done, а не только при замене всего массива.
Опции
| Опция | Что делает |
|---|---|
deep: true | Следит за изменениями вложенных полей |
immediate: true | Вызывает функцию сразу при создании, а не только при изменении |
once: true | Срабатывает только один раз |
Отслеживание части объекта
Чтобы следить за одним полем, передайте функцию-геттер, которая его возвращает:
<script setup>
import { ref, watch } from 'vue'
const filter = ref({ query: '', onlyActive: false })
watch(() => filter.value.onlyActive, (value) => {
console.log('Только активные:', value)
})
</script>Наблюдатель сработает при переключении onlyActive, а изменения query проигнорирует.
Функция watchEffect
watchEffect сам определяет зависимости: он выполняет функцию сразу и запоминает, какие реактивные данные она прочитала.
<script setup>
import { ref, watchEffect } from 'vue'
const todos = ref([])
watchEffect(() => {
document.title = `Задач: ${todos.value.length}`
})
</script>Заголовок вкладки браузера сразу станет «Задач: 0» и будет меняться при каждом добавлении или удалении задачи.
watch | watchEffect | |
|---|---|---|
| Источник | Указывается явно | Определяется сам |
| Первый запуск | При изменении | Сразу |
| Старое значение | Есть | Нет |
Частая ошибка
Передать в watch значение вместо источника:
<script setup>
watch(filter.value.query, (value) => { /* ... */ })
</script>filter.value.query — это просто строка на момент вызова, Vue выведет предупреждение и не будет следить за ней. Передавайте сам ref или функцию: watch(() => filter.value.query, ...).