Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Передача данных вглубь: provide и inject

Иногда данные нужны компоненту, который лежит на несколько уровней ниже: App.vue → TodoList.vue → TodoItem.vue. Передавать их через props каждого промежуточного компонента утомительно. Функция provide делает значение доступным всем потомкам, а inject достаёт его там, где оно нужно.

Предоставить значение

В src/App.vue вызовите provide с ключом и значением:

<!-- src/App.vue -->
<script setup>
import { ref, provide } from 'vue'
import TodoList from './components/TodoList.vue'
 
const theme = ref('light')
provide('theme', theme)
</script>
 
<template>
  <button @click="theme = theme === 'light' ? 'dark' : 'light'">
    Сменить тему
  </button>
  <TodoList />
</template>

Ключ 'theme' — имя, по которому потомки найдут значение. Передан сам ref, поэтому потомки увидят его изменения.

Получить значение

В любом вложенном компоненте, например src/components/TodoItem.vue, вызовите inject с тем же ключом:

<!-- src/components/TodoItem.vue -->
<script setup>
import { inject } from 'vue'
 
defineProps({ todo: Object })
 
const theme = inject('theme')
</script>
 
<template>
  <li :class="theme">{{ todo.text }}</li>
</template>
 
<style scoped>
.dark {
  background: #222;
  color: #eee;
}
</style>

Кнопка «Сменить тему» в App.vue переключает фон всех задач на тёмный и обратно. TodoList ничего не знает о теме и не передаёт её.

Значение по умолчанию

Если ни один предок не вызвал provide с этим ключом, inject вернёт undefined и Vue выведет предупреждение. Второй аргумент задаёт запасное значение:

<script setup>
import { inject } from 'vue'
 
const theme = inject('theme', 'light')
</script>

Так компонент будет работать и вне App.vue, например в тесте.

Изменения только у владельца

Чтобы потомки не меняли общее значение как попало, вместе с ним передают функцию для изменения:

<!-- src/App.vue -->
<script setup>
import { ref, provide, readonly } from 'vue'
 
const theme = ref('light')
 
function toggleTheme() {
  theme.value = theme.value === 'light' ? 'dark' : 'light'
}
 
provide('theme', { theme: readonly(theme), toggleTheme })
</script>
<!-- src/components/ThemeButton.vue -->
<script setup>
import { inject } from 'vue'
 
const { theme, toggleTheme } = inject('theme')
</script>
 
<template>
  <button @click="toggleTheme">Тема: {{ theme }}</button>
</template>

readonly возвращает версию ref, которую нельзя изменить. Менять тему можно только через toggleTheme — код изменения остаётся в одном месте.

Когда что использовать

СитуацияСпособ
Данные нужны прямому потомкуprops
Одно значение для целой ветки дерева: тема, языкprovide и inject
Общие данные всего приложения: пользователь, корзинаХранилище Pinia (глава про Pinia)

Частая ошибка

Передать в provide значение вместо ref: provide('theme', theme.value). Потомки получат строку 'light' на момент вызова и никогда не узнают о смене темы. Передавайте сам ref — так связь сохраняется.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.