React

Ref vs. Reactive - Pick one, Kill the Other

Reactive data declaration is arguably the most complex part of the Composition API. Not only we must choose between ref and reactive, but…

Fotis Adamakis
Fotis Adamakis
Senior Software Engineer / Technical Writer
3 min read
February 29, 2024

Ref vs. Reactive - Pick one, Kill the Other

Ref vs. Reactive - Pick one, Kill the Other

Reactive data declaration is arguably the most complex part of the Composition API. Not only we must choose between ref and reactive, but we also have to handle each differently afterwards. This is because reactive seamlessly works with complex types, while ref wraps the variable in a new object and requires .value to access the value.

Adding to the confusion, when using refs in templates, the values are automatically unwrapped and .value can be omitted. However, this unwrapping only applies to the top-level properties.

Read more about [why both Ref and Reactive are needed](/vue-3-why-both-ref-and-reactive-are-needed-344bb5da2593).

Another issue that often arises with reactive is that [reactivity is lost after a reassignment](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#limitations-of-reactive).

<script setup>
import { ref, reactive } from "vue";

let response = reactive();
let loading = ref(false);

async function fetchData() {
  loading.value = true;
  response = await apiCall(); // this assignment breaks reactivity
  loading.value = false;
}

fetchData();
</script>

Thinking long term I believe only one of them will survive and will be widely adopted. But which one is the best?

The Case for Reactive

We can use reactive in all cases by following the Options API paradigm and utilizing an object to hold all of our state.

<script setup>
import { reactive } from "vue";

const state = reactive({
  response: [],
  loading: false,
});

async function fetchData() {
  state.loading = true;
  state.response = await apiCall();
  state.loading = false;
}

fetchData();
</script>

This may seem acceptable in this simplified example, but in more complex real-world components, we lose one of the most important benefits of the Composition API, which is the grouping of related functionality together.

Ref vs. Reactive - Pick one, Kill the Other

This advantage, when combined with the abstraction of code through composables, can significantly simplify our components and make them more comprehensible. Therefore, grouping unrelated variables together is likely not a wise choice.

The Case for Ref

Ref can also be used for all purposes, with the important note that complex types require the use of the .value suffix to read or update a variable’s content.

<script setup>
import { ref } from "vue";

const response = ref([]);
const loading = ref(false);

async function fetchData() {
  loading.value = true;
  response.value = await apiCall();
  loading.value = false;
}

fetchData();
</script>

Adopting a single method for declaring data can significantly reduce mental overhead. While forgetting to use .value is sometimes unavoidable, Volar is always there to remind us.

Using ref is actually the recommended way to declare reactive state in vue official documentation.

Ref vs. Reactive - Pick one, Kill the Other

[https://vuejs.org/guide/essentials/reactivity-fundamentals.html](https://vuejs.org/guide/essentials/reactivity-fundamentals.html)

Conclusion

Predicting the future is never easy, but I doubt that both ref and reactive will be around in 5 years. Having one approach for handling variables could reduce the mental overhead, allowing us to focus more on delivering actual business value. Of course, the potential for some yet-to-exist experimental feature to offer better ergonomics and replace both always exists. An example of this was the [reactivity transform](https://vuejs.org/guide/extras/reactivity-transform), which ultimately led to more confusion than clarity and was therefore dropped.

The future is unpredictable, but if I were to place a bet, my money would be on ref being the only way of declaring reactive state in the near future.

Fotis Adamakis

Fotis Adamakis

Senior Software Engineer / Technical Writer

Experienced software engineer writing about front end architecture, accessibility, system design, and developer productivity. Lessons from building and maintaining large-scale frontend applications, with a focus on practical patterns that make codebases easier to understand, scale, and evolve.

Barcelona, Spain