I have an app that, among other things, keeps track of items in lists. The following example, a slight extension of the docs example (using props), works properly.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue List Component Test</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app"></div>
<script src="./app.js"></script>
</body>
</html>
app.js (with props)
const MyApp = {
data() {
return {
items: []
}
},
template: `<list-count></list-count><list :itemList="items"></list>`,
methods: {
addItem(i) {
this.items.push(i)
}
},
provide() {
return {
listLength: Vue.computed(() => this.items.length)
}
},
}
const app = Vue.createApp(MyApp)
const ItemListCount = {
inject: ["listLength"],
template: `<p> {{ this.listLength }}</p>`
}
const ItemList = {
props: ["itemList"],
template:`<ul>
<list-item v-for="(item, index) in itemList" :i="item" :idx="index"></list-item>
</ul>`
}
const ItemListItem = {
props: ["i", "idx"],
template: `<li>{{ idx }}, {{ i.message }}</li>`
}
app.component("list", ItemList)
app.component("list-item", ItemListItem)
app.component("list-count", ItemListCount)
const vm = app.mount('#app')
Because the item lists sit in components that are subject to routing, I'd rather use Provide/Inject vs. having to figure out how to pass props down the chain and through the router. The following app.js, which uses provide/inject instead of props for the list, does not work.
app.js (with provide/inject) ... note the removal of the :itemList binding, the addition of the itemList in provide(), and the change in the ItemList component to use inject instead of props.
const MyApp = {
data() {
return {
items: []
}
},
template: `<list-count></list-count><list></list>`,
methods: {
addItem(i) {
this.items.push(i)
}
},
provide() {
return {
listLength: Vue.computed(() => this.items.length),
itemList: Vue.computed(() => this.items)
}
},
}
const app = Vue.createApp(MyApp)
const ItemListCount = {
inject: ["listLength"],
template: `<p> {{ this.listLength }}</p>`
}
const ItemList = {
inject: ["itemList"],
template:`<ul>
<list-item v-for="(item, index) in itemList" :i="item" :idx="index"></list-item>
</ul>`
}
const ItemListItem = {
props: ["i", "idx"],
template: `<li>{{ idx }}, {{ i.message }}</li>`
}
app.component("list", ItemList)
app.component("list-item", ItemListItem)
app.component("list-count", ItemListCount)
const vm = app.mount('#app')
The above raises the following error in console:
Uncaught TypeError: i is undefined
I assume the error is because the v-for loop isn't working properly with the inject: ["itemList"] whereas it seems to be working fine with a props: ["itemList"]. I can't find any relevant docs that would explain why this is the case. How do I fix the provide/inject version?