Fornecer / Injetar
Esta página presume que já fizeste leitura dos Fundamentos de Componentes. Leia aquele primeiro se fores novo para os componentes.
Perfuração de Propriedade
Usualmente, quando precisamos passar dados do componente pai para um componente filho, utilizamos as propriedades. No entanto, imagine o caso onde temos uma grande árvore de componente, e um componente encaixado profundamente precisa de alguma coisa de um componente ancestral distante. Apenas com as propriedades, teríamos de passar a mesmo propriedade através da corrente do componente pai inteira:
Repara que apesar do componente <Footer>
pode não importar-se com estas propriedades absolutamente, ele ainda precisa declarar e passá-los exatamente juntos assim o <DeepChild>
pode acessá-los. Se existir uma corrente pai mais longa, mais componentes seriam afetadas ao longo do caminho. Isto é chamado "perfuração de propriedade" e definitivamente não é divertido de se lidar.
Nós podemos resolver a perfuração de propriedades com provide
e inject
. Um componente pai pode servir como um fornecedor de dependência para todos os seus descendentes. Qualquer componente na árvore de descendência, independentemente de quão profundo ele esteja, pode injetar as dependências fornecidas pelos componentes para cima na corrente do seu componente pai.
Fornecer
Para fornecer dados aos descendentes do componente, utilize a função provide()
:
vue
<script setup>
import { provide } from 'vue'
provide(/* chave */ 'message', /* valor */ 'hello!')
</script>
Se estiveres utilizando o <script setup>
, certifica-te de que provide()
seja chamada de maneira síncrona dentro da setup()
:
js
import { provide } from 'vue'
export default {
setup() {
provide(/* chave */ 'message', /* valor */ 'hello!')
}
}
A função provide()
aceita dois argumentos. O primeiro argumento é chamado de chave da injeção, a qual pode ser uma sequência de caracteres ou um Symbol
. A chave da injeção é utilizada pelos componentes descendentes para pesquisar o valor desejado para injetar. Um único componente pode chamar provide()
várias vezes com chaves de injeção diferentes para fornecer valores diferentes.
O segundo argumento é o valor fornecido. O valor pode ser de qualquer tipo, incluindo estado reativo tais como referências:
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
O fornecimento de valores reativos permite os componentes descendentes utilizar o valor fornecido para estabelecer uma conexão reativa para componente fornecedor.
Fornecimento a Nível de Aplicação
Além do fornecimento de dados em um componente, podemos também fornecer no nível da aplicação:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* chave */ 'message', /* valor */ 'hello!')
Os fornecimentos de nível da aplicação estão disponíveis para todos os componentes interpretados na aplicação. Isto é especialmente útil quando estamos escrevendo extensões, visto que as extensões normalmente não seriam capazes de fornecer valores utilizando componentes.
Injetar
Para injetar os dados fornecidos por um componente ancestral, utilize a função inject()
:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
Se o valor fornecido for uma referência, ela será injetada como está e não será automaticamente desembrulhada. Isto permite o componente injetor conservar a conexão de reatividade para o componente fornecedor.
Exemplo de fornecer + injetar com Reatividade completo
Novamente, se não estiveres utilizando <script setup>
, inject()
deve apenas ser chamada de maneira síncrona dentro de setup()
:
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
Valores Padrão da Injeção
Por padrão, a inject
presume que a chave injetada é fornecida em algum lugar na corrente do componente pai. No caso onde a chave não é fornecida, haverá um aviso de tempo de execução.
Se queremos fazer uma propriedade injetada funcionar com fornecedores opcionais, precisamos declarar um valor padrão, semelhante as propriedades:
js
// `value` será "default value"
// se nenhum dado correspondendo "message" foi passado
const value = inject('message', 'default value')
Em alguns casos, o valor padrão pode precisar ser criado chamando uma função ou instanciando uma nova classe. Para evitar cálculo desnecessário ou efeitos colaterais no caso do valor opcional não for passado, podemos utilizar uma função de fábrica ("factory function", se preferires) para criação do valor padrão:
js
const value = inject('key', () => new ExpensiveClass())
Trabalhando com Reatividade
Quando estiveres utilizando os valores reativos de fornecer e injetar, é recomendado manter quaisquer mutações para o estado reativo dentro do fornecedor sempre que possível. Isto garante que o estado fornecido e suas possíveis mutações são co-localizados no mesmo componente, tornando mais fácil manter no futuro.
Talvez exista momentos em que precisamos atualizar os dados a partir de um componente injetor. Em tais casos, recomendamos o fornecimento de uma função que seja responsável pela mutação do estado:
vue
<!-- dentro do componente fornecedor -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>
vue
<!-- no componente injetor -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
Finalmente, podes envolver o valor fornecido com a readonly()
se quiseres garantir que os dados passados através de provide
não possam ser alterados pelo componente injetado.
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>
Trabalhando com Chaves de Symbol
Até aqui, temos estado utilizando chaves de injeção de sequência de caracteres nos exemplos. Se estiveres trabalhando em uma aplicação grande com vários provedores de dependência, ou estiveres criando componentes que serão utilizados por outros programadores, é melhor utilizar as chaves de injeção de Symbol
("Símbolo") para evitar potenciais colisões.
É recomendado exportar os símbolos em um ficheiro dedicado:
js
// keys.js
export const myInjectionKey = Symbol()
js
// no componente fornecedor
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* dados a fornecer */
})
js
// no componente injetor
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
Consulte também: Tipando provide
/ inject