Skip to content

Commit 16a5e29

Browse files
author
ntepluhina
committed
feat: described provide-inject basics
1 parent 2c3c9e4 commit 16a5e29

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

src/.vuepress/config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ module.exports = {
5050
'component-registration',
5151
'component-props',
5252
'component-custom-events',
53-
'component-slots'
53+
// 'component-slots',
54+
// 'component-dynamic-async',
55+
'component-provide-inject'
5456
]
5557
}
5658
]

src/guide/component-provide-inject.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Provide / Inject
2+
3+
> This page assumes you've already read the [Components Basics](components.md). Read that first if you are new to components.
4+
5+
Usually, when we need to pass data from the parent to child component, we use [props](component-props.md). Imagine the structure where you have some deeply nested components and you only need something from the ancestor component in the far descendant. In this case, you still need to pass the prop down the whole component chain which might be annoying.
6+
7+
For such cases, we can use the `provide` and `inject` pair. Ancestor components can serve as dependency injector for all its descendants, regardless how deep the component hierarchy is. This feature works on two parts: ancestor component has a `provide` option to provide data and descendant component has an `inject` option to start using this data.
8+
9+
For example, if we have a hierarchy like this:
10+
11+
```
12+
Root
13+
└─ TodoList
14+
├─ TodoItem
15+
└─ TodoListFooter
16+
├─ ClearTodosButton
17+
└─ TodoListStatistics
18+
```
19+
20+
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:
21+
22+
```js
23+
const app = Vue.createApp({})
24+
25+
app.component('todo-list', {
26+
data() {
27+
return {
28+
todos: ['Feed a cat', 'Buy tickets']
29+
}
30+
},
31+
provide: {
32+
foo: 'bar'
33+
},
34+
template: `
35+
<div>
36+
{{ todos.length }}
37+
<!-- rest of the template -->
38+
</div>
39+
`
40+
})
41+
42+
app.component('todo-list-statistics', {
43+
inject: ['foo'],
44+
created() {
45+
console.log(`Injected property: ${this.foo}`) // > Injected property: bar
46+
}
47+
})
48+
```
49+
50+
However, this won't work if we try to provide some Vue instance property here:
51+
52+
```js
53+
app.component('todo-list', {
54+
data() {
55+
return {
56+
todos: ['Feed a cat', 'Buy tickets']
57+
}
58+
},
59+
provide: {
60+
foo: this.todos.length // this will result in error 'Cannot read property 'length' of undefined`
61+
},
62+
template: `
63+
...
64+
`
65+
})
66+
```
67+
68+
To access Vue instance properties, we need to convert `provide` to be a function returning an object
69+
70+
```js
71+
app.component('todo-list', {
72+
data() {
73+
return {
74+
todos: ['Feed a cat', 'Buy tickets']
75+
}
76+
},
77+
provide() {
78+
return {
79+
foo: this.todos.length
80+
}
81+
},
82+
template: `
83+
...
84+
`
85+
})
86+
```
87+
88+
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.
89+
90+
In fact, you can think of dependency injection as sort of “long-range props”, except:
91+
92+
- ancestor components don’t need to know which descendants use the properties it provides
93+
- descendant components don’t need to know where injected properties are coming from
94+
95+
## Working with reactivity

0 commit comments

Comments
 (0)