-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Provide/inject #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Provide/inject #48
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
21df49d
Fixed an example
fc03746
feat: added component-slots
5258c66
Merge branch 'master' into component-slots
2c3c9e4
fix: fixed config
21ca76b
Update src/guide/component-slots.md
NataliaTepluhina 895731f
Update src/guide/component-slots.md
NataliaTepluhina 877a318
Update src/guide/component-slots.md
NataliaTepluhina 1c0dc36
Update src/guide/component-slots.md
NataliaTepluhina 3f36e0d
Update src/guide/component-slots.md
NataliaTepluhina 3de6a32
fix: fixed default slot wrapping
fbae532
fix: fixed compilation scope name
79804e8
feat: described provide-inject basics
d2dfb57
feat: started reactive provide/inject
6c8123a
Merge branch 'master' into component-dependency-injection
28b7ec9
fix: added provide-inject illustration
163ded6
fix: changed the name to dependency provider
4690f3c
fix: fixed examples
8a80fd6
Update src/guide/component-provide-inject.md
NataliaTepluhina 8039968
Update src/guide/component-provide-inject.md
NataliaTepluhina c169ff9
Update src/guide/component-provide-inject.md
NataliaTepluhina fbc6428
fix: fixed vuepress config
8e6506e
Merge branch 'master' into component-dependency-injection
NataliaTepluhina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Provide / inject | ||
|
||
> This page assumes you've already read the [Components Basics](components.md). 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](component-props.md). 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. | ||
|
||
 | ||
|
||
For example, if we have a hierarchy like this: | ||
|
||
``` | ||
Root | ||
└─ TodoList | ||
├─ TodoItem | ||
└─ TodoListFooter | ||
├─ ClearTodosButton | ||
└─ TodoListStatistics | ||
``` | ||
|
||
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: | ||
|
||
```js | ||
const app = Vue.createApp({}) | ||
|
||
app.component('todo-list', { | ||
data() { | ||
return { | ||
todos: ['Feed a cat', 'Buy tickets'] | ||
} | ||
}, | ||
provide: { | ||
user: 'John Doe' | ||
}, | ||
template: ` | ||
<div> | ||
{{ todos.length }} | ||
<!-- rest of the template --> | ||
</div> | ||
` | ||
}) | ||
|
||
app.component('todo-list-statistics', { | ||
inject: ['foo'], | ||
created() { | ||
console.log(`Injected property: ${this.user}`) // > Injected property: John Doe | ||
} | ||
}) | ||
``` | ||
|
||
However, this won't work if we try to provide some Vue instance property here: | ||
|
||
```js | ||
app.component('todo-list', { | ||
data() { | ||
return { | ||
todos: ['Feed a cat', 'Buy tickets'] | ||
} | ||
}, | ||
provide: { | ||
todoLength: this.todos.length // this will result in error 'Cannot read property 'length' of undefined` | ||
}, | ||
template: ` | ||
... | ||
` | ||
}) | ||
``` | ||
|
||
To access Vue instance properties, we need to convert `provide` to be a function returning an object | ||
|
||
```js | ||
app.component('todo-list', { | ||
data() { | ||
return { | ||
todos: ['Feed a cat', 'Buy tickets'] | ||
} | ||
}, | ||
provide() { | ||
return { | ||
todoLength: this.todos.length | ||
} | ||
}, | ||
template: ` | ||
... | ||
` | ||
}) | ||
``` | ||
|
||
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 want to react to changes in the ancestor component, we need to assign a Composition API `computed` property to our provided `todoLength`: | ||
|
||
```js | ||
app.component('todo-list', { | ||
// ... | ||
provide() { | ||
return { | ||
todoLength: Vue.computed(() => this.todos.length) | ||
} | ||
} | ||
}) | ||
``` | ||
|
||
In this, any change to `todos.length` will be reflected correctly in the components, where `todoLength` is injected. Read more about `reactive` provide/inject in the [Composition API section](TODO) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've started this chapter here but the more I work on it the more I think it should belong to Composition API. Maybe it would be a good idea to just state
provide/inject is not reactive by default
and say that if you want to make it reactive, you should look into Composition API chapterMaking provide/inject reactive
or something like this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel same, we can introduce to idea here and expand on reactivity on composition API section. However, in my opinion, the following section should be here and we can further link it composition API section.