Search code examples
vue.jsvue-componentvuejs3vue-composition-apivue-reactivity

What is the difference between ref, toRef and toRefs?


I have just started working with Vue 3 and the Composition API.

What are the differences between ref, toRef and toRefs?


Solution

  • Vue 3 ref

    A ref is a mechanism for reactivity in Vue 3. The idea is to wrap a non-object variable inside a reactive object:

    Takes an inner value and returns a reactive and mutable ref object. The ref object has a single property .value that points to the inner value.

    Hmm.. Why?

    Vue 3 relies on JavaScript proxies to detect changes to your reactive data and implement the reactivity. Proxies are essentially event listeners for objects: any reading or writing on a proxied object triggers the proxy, which can then do something with the values. This is convenient for reactivity since the variable changing will provide a trigger from which Vue can update any dependencies.

    But proxies require objects to work. So Vue provides the ref method to convert your non-object variables into objects and then to grant reactive capabilities through a proxy. (Objects are reference variables, hence the name ref.)

    (And Vue automatically unwraps your refs in the template, which is an added benefit of ref that you wouldn't get if you wrapped your value variables in an object manually.)

    reactive

    If your original variable is already an object (or array), a ref wrapping is not *usually needed because it is already a reference type. It only needs Vue's reactive functionality (which a ref also has):

    const state = reactive({
      foo: 1,
      bar: 2
    })
    

    But now consider copying a property from the object above to a new variable, for example foo which contains the number 1. If you copied this to a new variable, the copy would of course be a regular, non-reactive variable having no connection to the reactive object it was copied from. If foo changed later, the copy would not, meaning the copy is not reactive. This is where toRef is useful.

    toRef

    toRef converts a single reactive object property to a ref that maintains its connection with the parent object:

    const state = reactive({
      foo: 1,
      bar: 2
    })
    
    const fooRef = toRef(state, 'foo')
    /*
    fooRef: Ref<number>,
    */
    

    Now if state.foo changes, fooRef.value will change as well. So toRef has enabled copying a value property in such a way that the copy also has a reactive connection to the original parent object.

    toRefs

    toRefs converts all of the object's properties, to a new plain object having properties that are refs:

    const state = reactive({
      foo: 1,
      bar: 2
    })
    
    const stateAsRefs = toRefs(state)
    /*
    {
      foo: Ref<number>,
      bar: Ref<number>
    }
    */
    

    When would I ever use toRef or toRefs?

    The most likely time would be when importing a reactive object that has value properties like the example, such as from a composable, and destructuring it. The act of destructuring will pull the current property value from the object into a new local variable that will not be reactive without toRef. You may notice this when importing and destructuring a Pinia store into your component, for example.

    * Sometimes a ref is useful even on objects/arrays. For example, if you want to declare a variable to be set later by an async result