Vue 3 Composition API - "ref" and "reactive"
Tags: vue3vue
Published: 2021-04-07 02:46:56

---
title: Vue 3 Composition API - "ref" and "reactive"
published: true
date: 2021-03-23 14:11:24 UTC
tags: vue3vue
canonical_url: https://www.thisdot.co/blog/vue-3-composition-api-ref-and-reactive
---

## Introduction

With the release of Vue 3, developers now have access to the Composition API, a new way to write Vue components. This API allows features to be grouped together logically, rather than having to organize your single-file components by function. Using the Composition API can lead to more readable code, and gives the developer more flexibility when developing their applications.

The Composition API provides two different ways to store data locally in the component - “ref” and “reactive”. These two methods serve a similar role as the “data” function in the traditional Options API that is commonly used in Vue applications today. In this article, we will explore both of these new methods, and when to use them in your own application.

If you want to read more about the Composition API, you can read [this article by Bilal Haidar](https://labs.thisdot.co/blog/vue-3-composition-api-do-you-really-need-it "Vue 3 Composition API - do you really need it?") for an overview.

You can view the code examples below in a working app on CodeSandbox by [clicking this link](https://codesandbox.io/s/ref-vs-reactive-rzf6q).

## Options API - `data`

If you have used Vue in the past, you have probably seen how different parts of your components are divided by function. Each single-file component has access to a number of attributes: data, computed, methods, lifecycle hooks, and so on. This is referred to as the "Options API". Below is an example application implementing local state with the Options API:

```
<template>
  <button @click="count++">count is: {{ count }}</button>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "App",
  data() {
    return {
      count: 0
    };
  }
});
</script>
```

## Composition API - `ref`

Now let's look at the same example as above, using the Composition API. First, we'll take a look at `ref`. [From the Vue 3 documentation](https://v3.vuejs.org/api/refs-api.html "Refs API"):

> ref 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.

Below is our example code using `ref`:

```
<template>
  <button @click="count++">count is: {{ count }}</button>
</template>

<script lang="ts">
import { ref, defineComponent } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const count = ref(0);

    return { count };
  },
});
</script>
```

Let's take a closer look. What changed between these two examples?

1. Rather than using the `data` function to add local state, we are using the `setup` function. This new function replaces `data`, `beforeCreate`, and `created`, and is the place for utilizing the Composition API.
2. Like with `data`, `setup` returns an object. The contents of that object is any variable that needs to be accessible from the template. Since we want the count to be available in the template, we include it in the return object.

Before we continue to `reactive`, we should make one more change. Let's move the click event into its own method, rather than performing the action in the template.

```
<template>
  <button @click="increaseCount">count is: {{ count }}</button>
</template>

<script lang="ts">
import { ref, defineComponent } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const count = ref(0);

    const increaseCount = () => {
      count.value++;
    }

    return { count, increaseCount };
  },
});
</script>
```

Unlike in the Options API, methods are simply functions. We don't need any special syntax or Composition API methods to make them work. However, just like the `count` variable above, we do need to return the method from the `setup` function in order for it to be available in the template.

Notice that in the template, we used `count++` to increase the value, but in the `setup` function, we use `count.value`. This is because in the `setup` function, `count` has a type of `Ref<number>`, where in the template the internal value is directly available.

## Composition API - `reactive`

Now let's try out the `reactive` method. [From the Vue 3 docs](https://v3.vuejs.org/api/basic-reactivity.html#reactive "Basic Reactivity"):

> reactive returns a reactive copy of the object. The reactive conversion is "deep"—it affects all nested properties. In the [ES2015 Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy "Proxy - MDN") based implementation, the returned proxy is not equal to the original object. It is recommended to work exclusively with the reactive proxy, and avoid relying on the original object.

Here is our code example using `reactive` instead of `ref`:

```
<template>
  <button @click="increaseCount">count is: {{ state.count }}</button>
</template>

<script lang="ts">
import { reactive, defineComponent } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const state = reactive({
      count: 0
    });

    const increaseCount = () => {
      state.count++;
    }

    return { state, increaseCount };
  },
});
</script>
```

Within the `setup` function, we can use the return value of `reactive` very similarly to how we use the `data` function in the Options API. Because the object is deeply reactive, we can also make changes to it directly. So instead of `count.value++`, we can simply increment the value with `state.value++`.

## When to use `ref` and `reactive`

In general, `ref` is useful for primitives (string, number, boolean, etc), and `reactive` is useful for objects and arrays. However, there are some key points to consider:

First, if you pass an object into a `ref` function call, it will return an object that has been passed through `reactive`. The below code works perfectly fine:

```
<template>
  <button @click="increaseCount">count is: {{ state.count }}</button>
</template>

<script lang="ts">
import { ref, defineComponent } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const state = ref({
      count: 0
    });

    const increaseCount = () => {
      state.value.count++;
    }

    return { state, increaseCount };
  },
});
</script>
```

Second, while the object returned from `reactive` is deeply reactive (setting any value to the object will trigger a reaction in Vue), you can still accidentally make the values non-reactive. If you try to destructure or spread the values of the object, for example, they will no longer be reactive. The below code does _not_ work as you might expect:

```
<template>
  <button @click="increaseCount">count is: {{ count }}</button>
</template>

<script lang="ts">
import { reactive, defineComponent } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const state = reactive({
      count: 0
    });

    const increaseCount = () => {
      state.count++;
    }

    return { ...state, increaseCount };
  },
});
</script>
```

If you want to do something like this, Vue 3 has you covered. There are a number of functions to convert between Refs and their values. In this case, we will use the `toRefs` function. [From the docs:](https://v3.vuejs.org/api/refs-api.html#torefs "Refs API")

> Converts a reactive object to a plain object where each property of the resulting object is a ref pointing to the corresponding property of the original object.

If we update our above code example to spread the result of `toRefs`, then everything works as we'd expect:

```
<template>
  <button @click="increaseCount">count is: {{ count }}</button>
</template>

<script lang="ts">
import { toRefs, reactive, defineComponent } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const state = reactive({
      count: 0
    });

    const increaseCount = () => {
      state.count++;
    }

    return { ...toRefs(state), increaseCount };
  },
});
</script>
```

There are other ways to combine these two functions, both with setting a value in a `reactive` object to its own variable with `toRef` or adding a `ref` to an object directly. `ref` and `reactive` are two parts of the solution, and you will find yourself reaching for each of them as needed.

## Conclusion

The Vue 3 Composition API provides a lot of benefit to developers. By allowing features to be grouped together, rather than functions, developers can focus on what they are building, and less on fitting their code into a predetermined structure.

By leveraging the `ref` and `reactive` functions to maintain local state, developers have new tools to write more maintainable and readable code. These methods work well together, rather than one or the other, each solving a different problem.

Remember that the Composition API is optional! The existing Options API is not going anywhere, and will continue to work as expected. I would encourage you to try out the Composition API, and see how these new methods can improve your own workflow and applications.

To view the above examples in a working application, [click here](https://codesandbox.io/s/ref-vs-reactive-rzf6q) to view them in CodeSandbox.

_This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit [thisdotlabs.com](https://www.thisdotlabs.com)._

_This Dot Media is focused on creating an inclusive and educational web for all. We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit [thisdot.co](https://www.thisdot.co)._