Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
Vue 3 is in beta and it’s subject to change.
Vue 3 is the up and coming version of Vue front end framework.
It builds on the popularity and ease of use of Vue 2.
In this article, we’ll look at providing and injecting data with Vue 3.
Provide and Inject
To make passing data easier between deeply nested components, we can bypass props and use the provide
property to expose some data.
And then we can use the inject
property to get the data.
For example, we can write:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<blog-post></blog-post>
</div>
<script>
const app = Vue.createApp({});
app.component("blog-post", {
data() {
return {
post: { title: "hello world" }
};
},
provide: {
author: "james"
},
template: `
<div>
{{ post.title }}
<blog-post-statistics></blog-post-statistics>
</div>
`
});
app.component("blog-post-statistics", {
inject: ["author"],
template: `
<p>{{author}}</p>
`,
created() {
console.log(this.author);
}
});
app.mount("#app");
</script>
</body>
</html>
We have the blog-post
and blog-post-statistics
components.
In the blog-post
component, we have the provide
property with the author
property.
This is the data that we’re providing to child components.
Therefore, in the blog-post-statistics
component, we have the inject
property with an array of the property names that are in provide
that we want to get.
So author
in blog-post-statistics
would be author
in the template or this.author
in component methods.
However, this won’t work with Vue instance properties.
So if we have:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<blog-post></blog-post>
</div>
<script>
const app = Vue.createApp({});
app.component("blog-post", {
data() {
return {
post: { title: "hello world", author: "james" }
};
},
provide: {
post: this.post
},
template: `
<div>
{{ post.title }}
<blog-post-statistics></blog-post-statistics>
</div>
`
});
app.component("blog-post-statistics", {
inject: ["post"],
template: `
<p>{{post.author}}</p>
`,
created() {
console.log(this.post.author);
}
});
app.mount("#app");
</script>
</body>
</html>
Then nothing will be displayed.
To fix this, we got to pass in the property that has the value to provide
and change provide
to a function:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<blog-post></blog-post>
</div>
<script>
const app = Vue.createApp({});
app.component("blog-post", {
data() {
return {
post: { title: "hello world", author: "james" }
};
},
provide() {
return {
author: this.post.author
};
},
template: `
<div>
{{ post.title }}
<blog-post-statistics></blog-post-statistics>
</div>
`
});
app.component("blog-post-statistics", {
inject: ["author"],
template: `
<p>{{author}}</p>
`,
created() {
console.log(this.author);
}
});
app.mount("#app");
</script>
</body>
</html>
Now the provide
is a method of the blog-post
component instead of a property.
And we return what we want to provide to child components.
Working with Reactivity
Changes with reactive properties in the parent won’t be reflected in child components when we update them.
This is a problem that can be fixed by making the reactive property a computed property.
For instance, we can write:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<counter></counter>
</div>
<script>
const app = Vue.createApp({});
app.component("counter", {
data() {
return {
count: 0
};
},
provide() {
return { count: Vue.computed(() => this.count) };
},
template: `
<div>
<button @click='count++'>increment</button>
<count-display></count-display>
</div>
`
});
app.component("count-display", {
inject: ["count"],
template: `
<p>{{count.value}}</p>
`
});
app.mount("#app");
</script>
</body>
</html>
We have a counter
component with a provide
method that returns an object with the count
property.
Its value is a computed property with this.count
returned in the callback.
This way, the latest value will be propagated to the child component.
Then in the count-display
component, we can get the value with the value
property.
Conclusion
Provide and inject gives is a way to pass data to deeply nested components without using props.