ref vs reactive in Vue 3?

Looking at some examples of some people's preview tutorials for Vue 3. [Currently beta right now]

I've found two examples:

Reactive

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

Ref

<template>
  <div>
    <h2 ref="titleRef">{{ formattedMoney }}</h2>
    <input v-model="delta" type="number">
    <button @click="add">Add</button>
  </div>
</template>

<script>
import { ref, computed, onMounted } from "vue";

export default {
  setup(props) {
    // State
    const money = ref(1);
    const delta = ref(1);

    // Refs
    const titleRef = ref(null);

    // Computed props
    const formattedMoney = computed(() => money.value.toFixed(2));

    // Hooks
    onMounted(() => {
      console.log("titleRef", titleRef.value);
    });

    // Methods
    const add = () => (money.value += Number(delta.value));

    return {
      delta,
      money,
      titleRef,
      formattedMoney,
      add
    };
  }
};
</script>

Key Points

  • reactive() only takes objects, NOT JS primitives (String, Boolean, Number, BigInt, Symbol, null, undefined)
  • ref() is calling reactive() behind the scenes
  • Since reactive() works for objects and ref() calls reactive(), objects work for both
  • BUT, ref() has a .value property for reassigning, reactive() does not have this and therefore CANNOT be reassigned

Use

ref() when..

  • it's a primitive (for example 'string', true, 23, etc)
  • it's an object you need to later reassign (like an array - more info here)

reactive() when..

  • it's an object you don't need to reassign, and you want to avoid the overhead of ref()

In Summary

ref() seems like the way to go since it supports all object types and allows reassigning with .value. ref() is a good place to start, but as you get used to the API, know that reactive() has less overhead, and you may find it better meets your needs.

ref() Use-Case

You'll always use ref() for primitives, but ref() is good for objects that need to be reassigned, like an array.

setup() {
    const blogPosts = ref([]);
    return { blogPosts };
}
getBlogPosts() {
    this.blogPosts.value = await fetchBlogPosts();
}

The above with reactive() would require reassigning a property instead of the whole object.

setup() {
    const blog = reactive({ posts: [] });
    return { blog };
}
getBlogPosts() {
    this.blog.posts = await fetchBlogPosts();
}

reactive() Use-Case

A good use-case for reactive() is a group of primitives that belong together:

const person = reactive({
  name: 'Albert',
  age: 30,
  isNinja: true,
});

the code above feels more logical than

const name = ref('Albert');
const age = ref(30);
const isNinja = ref(true);

Useful Links

If you're still lost, this simple guide helped me: https://www.danvega.dev/blog/2020/02/12/vue3-ref-vs-reactive/

An argument for only ever using ref(): https://dev.to/ycmjason/thought-on-vue-3-composition-api-reactive-considered-harmful-j8c

The decision-making behind why reactive() and ref() exist as they do and other great information, the Vue Composition API RFC: https://vue-composition-api-rfc.netlify.app/#overhead-of-introducing-refs


There are some similarities between ref and reactive, in that they both provide a method to store data and allow that data to be reactive.

However:

High level differences:

You can’t use reactive() on primitives (strings, numbers, booleans) - that’s what you need refs for, because you will have situations where you need to have a “reactive boolean”, for example…

of course your can create an object that wraps the primitive value and make that reactive():

const wrappedBoolean = reactive({
  value: true
})

and just like that, you reinvented a ref.

Source: Vue forum discussion

Reactive

reactive takes the object and returns a reactive proxy to the original object.

Example

import {ref, reactive} from "vue";

export default {
  name: "component",
  setup() {
    const title = ref("my cool title")
    const page = reactive({
      contents: "meh?",
      number: 1,
      ads: [{ source: "google" }],
      filteredAds: computed(() => {
        return ads.filter(ad => ad.source === "google")
      })
    })
    
    return {
       page, 
       title
    }
  }
}

Explanation

In the above, Whenever we want to change or access the properties of page,
say page.ads, page.filteredAds will update via Proxies.


ref / reactive both are been used to create reactive object where the changes been tracked.

Ref :

It takes an primitives argument and return a reactive mutable object. The object has single property ‘value’ and it will point to the argument taken by it.

Reactive :

It takes a JavaScript object as a argument and returns Proxy based reactive copy of the object.

Ref vs Reactive :

Typically, ref and reactive both have been used to create reactive objects where ref is used to make the primitive values to be reactive (Boolean, Number, String). But reactive won’t work with primitives rather than it works for objects.

For further details : Refer Ref vs Reactive