I am test provide and inject method. I put datas, del-function in parent to provide, I put dynamic render in child using v-for='data' in datas...
The goal I want to implement is: when I press the "delete button"=>del-function in child, then datas in parent get an item deleted , and datas in parent provide get updated.
datas to do visual update. v-for re-render. [!!!]But when I press the "delete button" , datas updated ,but visually ,no one get deleted.
// parent vue file
<template>
<Reslist/>
</template>
<script>
import Reslist from './components/ResList.vue'
export default {
name: "App",
components: {
Reslist
},
provide() {
return {
datas: this.datas,
delData: this.delData,
};
},
data() {
return {
datas: [
{
id: 1,
name: "wawa",
age: "18",
},
{
id: 2,
name: "wmmmfwa",
age: "1128",
},
],
};
},
methods: {
delData(id) {
console.log('delete-id ='+ id);
const newDatas = this.datas.filter( element => element.id !== id);
this.datas = newDatas;
console.log( this.datas);
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
// child vue file
<template>
<div v-for='data in datas' :key="data.name">
<h2>{{data.name}}</h2>
<p>{{data.age}}</p>
<button @click='delData(data.id)'>delete</button>
</div>
</template>
<script>
export default {
inject:['datas','delData']
}
</script>
<style scoped>
div{
width: 18.75rem;
margin: 1.25rem auto;
border: solid 1px grey;
padding: 1.25rem;
}
</style>
I know how to use prop to pass data to child. I just want to know why [provide and inject] don't work?? In [provide],I already [datas = this.datas] , does my logic have mistakes?
Your injected data is not working in a reactive way, and per the Vue.js Documentation, in order for injected data to do this, you must provide it as a computed property by wrapping it in a computed() function:
Which states:
Working with Reactivity
In order to make injections reactively linked to the provider, we need to provide a computed property using the computed() function
In your case, it might look like this:
provide() {
return {
datas: computed(() => this.datas),
delData: this.delData,
};
},
Having said this, Vue is always undergoing updates, enhancements and fixes, and in order for this to work fully, temporarily, you must add an additional config to your application:
Which states:
Temporary Config Required
The above usage requires setting
app.config.unwrapInjectedRef = trueto make injections automatically unwrap computed refs. This will become the default behavior in Vue 3.3 and this config is introduced temporarily to avoid breakage. It will no longer be required after 3.3.
In code, this could look like so:
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
const app = createApp(App);
app.config.unwrapInjectedRef = true;
app.mount('#app')
Good night, Bro!
I found a solution using computed props...
Hope its helpful!
Parent Vue File
<template>
<Reslist/>
</template>
<script>
import Reslist from './ResList.vue'
import { computed } from '@vue/reactivity'
export default {
name: "App",
components: {
Reslist
},
provide() {
return {
datas: computed(() => this.datas),
delData: this.delData,
};
},
data() {
return {
datas: [
{
id: 1,
name: "wawa",
age: "18",
},
{
id: 2,
name: "wmmmfwa",
age: "1128",
},
],
};
},
methods: {
delData(id) {
console.log('delete-id ='+ id);
const newDatas = this.datas.filter( element => element.id !== id);
this.datas = newDatas;
console.log(this.datas);
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Child File
<template>
<div v-for='data in datas' :key="data.name">
<h2>{{data.name}}</h2>
<p>{{data.age}}</p>
<button @click='delData(data.id)'>delete</button>
</div>
</template>
<script>
export default {
inject:['datas','delData']
}
</script>
<style scoped>
div{
width: 18.75rem;
margin: 1.25rem auto;
border: solid 1px grey;
padding: 1.25rem;
}
</style>
Configuring Main.js To Accept Computed prop.
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.config.unwrapInjectedRef = true
app.mount('#app')
The information for this config : https://vuejs.org/guide/components/provide-inject.html#working-with-reactivity