Prop Drilling
Обычно, когда нам нужно передать данные от родительского компонента дочернему, мы используем props. Однако представьте себе случай, когда у нас есть большое дерево компонентов, и глубоко вложенному компоненту нужно что-то от компонента-предка. Если бы использовались только реквизиты, нам пришлось бы передавать один и тот же реквизит по всей родительской цепочке

Обратите внимание: хотя Footerкомпонент может вообще не заботиться об этих реквизитах, ему все равно необходимо объявить и передать их, чтобы DeepChildиметь к ним доступ. Если существует более длинная родительская цепочка, на этом пути будет затронуто больше компонентов. Это называется «сверлением реквизита», и заниматься этим определенно неинтересно
Мы можем решить проблему бурения реквизита с помощью provideи inject. Родительский компонент может служить поставщиком зависимостей для всех своих потомков. Любой компонент в дереве потомков, независимо от его глубины, может внедрять зависимости, предоставляемые компонентами в его родительской цепочке.

Provide
Чтобы предоставить данные потомкам компонента, используйте provide() функцию
Если вы не используете script setup, убедитесь, provide() что внутри он вызывается синхронно setup()
Функция provide() принимает два аргумента. Первый аргумент называется ключом внедрения, который может быть строкой или файлом Symbol. Ключ инъекции используется компонентами-потомками для поиска желаемого значения для внедрения. Один компонент может вызывать provide() несколько раз с разными ключами внедрения для предоставления разных значений
Второй аргумент — это предоставленное значение. Значение может быть любого типа, включая реактивное состояние
Предоставление реактивных значений позволяет компонентам-потомкам использовать предоставленное значение для установления реактивного соединения с компонентом-поставщиком.
App-level Provide
Помимо предоставления данных в компоненте, мы также можем предоставить на уровне приложения
Предоставления уровня приложения доступны для всех компонентов, отображаемых в приложении. Это особенно полезно при написании плагинов , поскольку плагины обычно не могут предоставлять значения с помощью компонентов
Inject
Чтобы внедрить данные, предоставленные компонентом-предком, используйте inject() функцию
Если предоставленное значение является ссылкой, оно будет введено как есть и не будет автоматически развернуто. Это позволяет компоненту-инжектору сохранять реактивное соединение с компонентом-поставщиком
Опять же, если не использовать script setup, inject() следует вызывать только синхронно внутри setup()
Значения по умолчанию
По умолчанию inject предполагается, что внедренный ключ предоставляется где-то в родительской цепочке. В случае, если ключ не предоставлен, во время выполнения будет выдано предупреждение
Если мы хотим, чтобы внедренное свойство работало с дополнительными поставщиками, нам нужно объявить значение по умолчанию, аналогичное свойствам
В некоторых случаях значение по умолчанию может потребоваться создать путем вызова функции или создания экземпляра нового класса. Чтобы избежать ненужных вычислений или побочных эффектов в случае, если необязательное значение не используется, мы можем использовать фабричную функцию для создания значения по умолчанию
Третий параметр указывает, что значение по умолчанию следует рассматривать как заводскую функцию
Работа с реактивностью
При использовании реактивных значений предоставления/внедрения рекомендуется по возможности сохранять любые изменения в реактивное состояние внутри провайдера . Это гарантирует, что предоставленное состояние и его возможные мутации будут размещены в одном компоненте, что упрощает поддержку в будущем.
Могут быть случаи, когда нам необходимо обновить данные компонента инжектора. В таких случаях мы рекомендуем предоставить функцию, отвечающую за изменение состояния
Наконец, вы можете обернуть предоставленное значение, readonly() если хотите гарантировать, что передаваемые данные provideне могут быть изменены компонентом инжектора
Работа с символьными клавишами
До сих пор в примерах мы использовали ключи внедрения строк. Если вы работаете в большом приложении со многими поставщиками зависимостей или создаете компоненты, которые будут использоваться другими разработчиками, лучше всего использовать ключи внедрения символов, чтобы избежать потенциальных коллизий.
Рекомендуется экспортировать символы в отдельный файл
Typing Provide / Inject
Обеспечение и внедрение обычно выполняются отдельными компонентами. Для правильного ввода введенных значений Vue предоставляет InjectionKey интерфейс, который является универсальным типом, расширяющим Symbol. Его можно использовать для синхронизации типа введенного значения между поставщиком и потребителем
Рекомендуется поместить ключ внедрения в отдельный файл, чтобы его можно было импортировать в несколько компонентов.
При использовании ключей внедрения строки тип введенного значения будет unknown, и его необходимо явно объявить с помощью аргумента универсального типа:
Обратите внимание, что введенное значение по-прежнему может быть undefined, поскольку нет гарантии, что поставщик предоставит это значение во время выполнения.
Тип undefined можно удалить, указав значение по умолчанию:
Если вы уверены, что значение всегда предоставляется, вы также можете принудительно привести его