Thomas Betous
Thomas Betous

Reputation: 5123

Why not reactive property are reactive in my template?

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

Answers (2)

Boussadjra Brahim
Boussadjra Brahim

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

Tim Dithmer
Tim Dithmer

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 refs 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

Related Questions