В Vue Router параметры маршрута (route params) и query-параметры по своей природе реактивны, но есть важные нюансы в работе с ними. Рассмотрим детально, как обеспечить правильную реактивность.
Самый надежный способ реагировать на изменения параметров:
import { watch } from 'vue'
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute()
watch(
() => route.params.id,
(newId, oldId) => {
console.log(`ID changed from ${oldId} to ${newId}`)
// Загрузка данных при изменении ID
fetchData(newId)
}
)
watch(
() => route.query,
(newQuery) => {
console.log('Query params changed:', newQuery)
},
{ deep: true }
)
}
}
Для производных значений от параметров маршрута:
import { computed } from 'vue'
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute()
const userId = computed(() => route.params.userId)
const searchQuery = computed(() => route.query.search || '')
return { userId, searchQuery }
}
}
Можно использовать beforeRouteUpdate:
export default {
beforeRouteUpdate(to, from, next) {
// Реакция на изменение параметров
if (to.params.id !== from.params.id) {
this.loadUserData(to.params.id)
}
next()
}
}
Повторное использование компонента: При изменении параметров в том же маршруте компонент не пересоздается, а повторно используется.
Массивы и объекты: Для глубокого наблюдения за объектами или массивами в query-параметрах нужно использовать { deep: true }
в watch.
Инициализация данных: Не забывайте загружать данные в created()/onMounted(), так как watch срабатывает только при изменениях.
import { ref, watch, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { fetchUserData } from '@/api/users'
export default {
setup() {
const route = useRoute()
const user = ref(null)
const loading = ref(false)
const error = ref(null)
const loadData = async (userId) => {
try {
loading.value = true
user.value = await fetchUserData(userId)
error.value = null
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}
// Загрузка при монтировании
onMounted(() => loadData(route.params.id))
// Реакция на изменение ID
watch(
() => route.params.id,
(newId) => {
if (newId) loadData(newId)
}
)
return { user, loading, error }
}
}
let abortController = null
watch(
() => route.params.id,
async (newId) => {
if (abortController) abortController.abort()
abortController = new AbortController()
try {
const data = await fetchData(newId, { signal: abortController.signal })
// обработка данных
} catch (err) {
if (err.name !== 'AbortError') {
// обработка ошибки
}
}
}
)
import { debounce } from 'lodash-es'
watch(
() => route.query.search,
debounce((newSearch) => {
searchProducts(newSearch)
}, 300)
)
В конфигурации маршрута:
{ path: '/user/:id', component: User, props: true }
В компоненте:
export default {
props: ['id'],
watch: {
id(newId) {
// Реакция на изменение id
}
}
}
watch
или computed
{ deep: true }
Правильная обработка реактивности параметров маршрута — ключ к созданию плавного пользовательского опыта в SPA-приложениях.