Reputation: 5123
I am currently working with the new reactivity API introduced in Vue.js 3. I have followed instructions on documentation and from what I understand when I set a variable with ref
I turn it into a reactive value. If I don't use ref
the variable is not reactive and should not be updated in the template if I update it.
I am suprised by the result of my test :
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<my-component></my-component>
</div>
<script>
const app = Vue.createApp({});
app.component("my-component", {
template: `
<div>
<ul>
<li>Data not reactive : {{ countNotReactive }}</li>
<li>Data reactive : {{ countReactive }}</li>
</ul>
<button @click="inc">+1</button>
</div>
`,
setup() {
const countNotReactive = 1;
const countReactive = Vue.ref(1);
return {
countNotReactive,
countReactive
};
},
methods: {
inc() {
this.countNotReactive++;
this.countReactive++;
}
}
});
app.mount("#app");
</script>
When I click on the +1 button, all the counter are incremented in my template. Here is the render :
<!-- Initial -->
<div>
<ul>
<li>Data not reactive : 1</li>
<li>Data reactive : 1</li>
</ul>
<button>+1</button>
</div>
<!-- After click on +1 -->
<div>
<ul>
<li>Data not reactive : 2</li>
<li>Data reactive : 2</li>
</ul>
<button>+1</button>
</div>
My expectation was to see only the reactive counter to be incremented. Does anyone can explain to me why it is not the case ?
I don't see why I should use ref
in this case. Does anyone can give me an example where I can see the difference between a ref and a non-ref variable ?
Upvotes: 1
Views: 1741
Reputation: 1
You could use both composition and option api in the same component but you shouldn't share methods and properties between the two API, your logic should be like :
const {
createApp
} = Vue;
const App = {
}
const app = createApp(App)
app.component("my-component", {
template: `
<div>
<ul>
<li>Data not reactive : {{ countNotReactive }}</li>
<li>Data reactive : {{ countReactive }}</li>
</ul>
<button @click="inc">+1</button>
</div>
`,
setup() {
const countNotReactive = 1;
const countReactive = Vue.ref(1);
function inc() {
countNotReactive++;
countReactive.value++;
}
return {
inc,
countNotReactive,
countReactive
};
},
});
app.mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
Vue 3 app
<my-component></my-component>
</div>
In reality the countNotReactive
is not changing as shown in the watch hook :
const {
createApp
} = Vue;
const App = {
}
const app = createApp(App)
app.component("my-component", {
template: `
<div>
<ul>
<li>Data not reactive : {{ countNotReactive }}</li>
<li>Data reactive : {{ countReactive }}</li>
</ul>
<button @click="inc">+1</button>
</div>
`,
setup() {
const countNotReactive = 1;
const countReactive = Vue.ref(1);
Vue.watch(countReactive,()=>{
console.log("countReactive",countReactive.value)
console.log("countNotReactive",countNotReactive)
})
return {
countNotReactive,
countReactive
};
},
methods: {
inc() {
this.countNotReactive++;
this.countReactive++;
}
}
});
app.mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
Vue 3 app
<my-component></my-component>
</div>
The behavior that you get is explained by the following code :
const myConst="I'm a constant"
console.log(myConst)
let obj={myConst} //adding myConst as property in obj which in our case is the `this` (vue instance)
console.log(obj.myConst)
obj.myConst="updated value"
console.log(obj.myConst)//this prints the updated value
//but if we try myConst="new value" this raises an error
console.log(myConst)//still the same as we declared
//conclusion : this.myConst is not the same as myConst
Upvotes: 1
Reputation: 428
You are using a mix of the Option API and the Composition API. With the Option API's method
Object, and the inc method within you create two variables
this.countNotReactive
this.countReactive
Those variables are taken in your template and override the variables which are returned from your Composition API's setup method.
Just don't mix that both and try it like this:
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<my-component></my-component>
</div>
<script>
const app = Vue.createApp({});
app.component("my-component", {
template: `
<div>
<ul>
<li>Data not reactive : {{ countNotReactive }}</li>
<li>Data reactive : {{ countReactive }}</li>
</ul>
<button @click="inc">+1</button>
</div>
`,
setup() {
const countNotReactive = 1;
const countReactive = Vue.ref(1);
const inc = () => {
countNotReactive++;
countReactive.value++;
}
return {
inc,
countNotReactive,
countReactive
};
},
});
app.mount("#app");
</script>
And that's where the difference is. A ref
s value is saved in its value
property, whereas a normal not reactive variable can be directly accessed. Look here: https://v3.vuejs.org/api/refs-api.html#ref
Upvotes: 4