This page assumes you've already read the Components Basics. Read that first if you are new to components.
Usually, when we need to pass data from the parent to child component, we use props. Imagine the structure where you have some deeply nested components and you only need something from the parent component in the deep nested child. In this case, you still need to pass the prop down the whole component chain which might be annoying.
For such cases, we can use the provide
and inject
pair. Parent components can serve as dependency provider for all its children, regardless how deep the component hierarchy is. This feature works on two parts: parent component has a provide
option to provide data and child component has an inject
option to start using this data.
However, the content of a button can be more than just plain text — it might contain any HTML markup, for example an icon or image, or even a nested Vue.js component. Also, using a slot more closely resembles the standard HTML tag, so such code is easier to write and understand. Vue.js nested slot. Share improve this question follow edited Jan 17 '19 at 20:22. Asked Jan 14 '19 at 23:12. Philllt Philllt. 3,451 3 3 gold badges 37 37 silver badges 52 52 bronze badges.
For example, if we have a hierarchy like this:
If we want to pass the length of todo-items directly to TodoListStatistics
, we would pass the prop down the hierarchy: TodoList
-> TodoListFooter
-> TodoListStatistics
. With provide/inject approach, we can do this directly:
Casio qv 11. However, this won't work if we try to provide some component instance property here:
To access component instance properties, we need to convert provide
to be a function returning an object
This allows us to more safely keep developing that component, without fear that we might change/remove something that a child component is relying on. The interface between these components remains clearly defined, just as with props.
In fact, you can think of dependency injection as sort of 'long-range props', except:
- parent components don't need to know which descendants use the properties it provides
- child components don't need to know where injected properties are coming from
# Working with reactivity
In the example above, if we change the list of todos
, this change won't be reflected in the injected todoLength
property. This is because provide/inject
bindings are not reactive by default. We can change this behavior by passing a ref
property or reactive
object to provide
. In our case, if we wanted to react to changes in the ancestor component, we would need to assign a Composition API computed
property to our provided todoLength
:
In this, any change to todos.length
will be reflected correctly in the components, where todoLength
is injected. Read more about computed
in the Computed and Watch section and reactive
provide/inject in the Composition API section.
<template> |
<manage-listsv-model='items'> |
<templatescope='{ item: user }'> |
{{ user.firstName }} {{ user.lastName }} |
template> |
manage-lists> |
template> |
<script> |
exportdefault { |
components: { |
ManageLists |
}, |
data() { |
return { |
items: [ |
{ firstName:'John', lastName:'Doe' }, |
{ firstName:'Renae', lastName:'McGillicuddy' } |
] |
}; |
} |
} |
script> |
<template> |
<div> |
<token-list :value='items' @input='forwardInput'> |
<templatescope='props'> |
<slotv-bind='props'>slot> |
template> |
token-list> |
<formclass='form' @submit.prevent='handleAdd'> |
<inputtype='text'placeholder='New Item'v-model='newItem'ref='newItem' /> |
<buttontype='submit'>Add Itembutton> |
form> |
div> |
template> |
<script> |
importTokenListfrom'./TokenList'; |
exportdefault { |
props: { |
value: { |
type:Array, |
default() { |
return []; |
} |
} |
}, |
components: { |
TokenList |
}, |
methods: { |
handleAdd() { |
this.$emit( 'input', this.value.concat( this.newItem ) ); |
this.newItem=''; |
this.$refs.newItem.focus(); |
}, |
forwardInput( payload ) { |
this.$emit( 'input', payload ); |
} |
} |
} |
script> |
<template> |
<divclass='token-list clearfix'> |
<divv-for='( item, index ) in value'class='token-item'> |
<slot :item='item' :index='index'> |
<span>{{ item }}span> |
<buttontype='button' @click='remove( index )'>×button> |
slot> |
div> |
div> |
template> |
<script> |
exportdefault { |
props: { |
value: { |
required:true |
} |
} |
methods: { |
remove( index ) { |
this.$emit( 'input', [ |
..this.value.slice( 0, index ), |
..this.value.slice( index +1 ) |
] ); |
} |
} |
} |
script> |