Reputation: 10404
Looking at some examples of some people's preview tutorials for Vue 3. [Currently beta right now]
I've found two examples:
<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>
<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>
Upvotes: 275
Views: 148639
Reputation: 51
It's easy to pick one:
ref
when you need to track the value replacement (if you re-assign value), be that complex or simple value. You will have to access it's contents via .value
.reactive
for objects and arrays.Keep in mind, that both reactive
and ref
(which uses reactive
under the hood) makes the passed object or array deep reactive, which adds some overhead. If you want to avoid that, I would suggest using shallowRef
and shallowReactive
instead.
See https://vuejs.org/api/reactivity-advanced.html for more details :)
Upvotes: 2
Reputation: 1254
Although others have already answered this question, I would like to summarize my understanding after conducting research. I believe this summary will be helpful for newbies who are just starting with Vue 3. Many thanks to all the posts and blogs in this thread.
Reactive
Limitationsconst reactiveNumber = reactive(0) // won't work
ref
has the .value
property to remind us that it holds reactive data, while reactive
objects lack this property. This can lead to loss of reactivity if not used carefully.let reactiveArray = reactive([1, 2, 3]);
let refArray = ref([1, 2, 3]);
setTimeout(() => {
// We've replaced it with an entirely new, non-reactive object
reactiveArray = [4, 5, 6];
refArray = [4, 5, 6]; // Warning when using with ref
}, 1000)
watchEffect(() => console.log(reactiveArray)); // Won't trigger for [4, 5, 6]
Ref
Limitationsref
value. Some places we can use a ref
directly, some places we have to use ref.value
. Doc<template>
<!-- Dont need .value because of ref template unwrapping -->
{{ refString }}
<button @click="mutateRef">Mutate</button>
<!-- Need .value if ref isnt a top-level property -->
<p>{{ user.age.value + 1 }}</p>
<!-- Dont need .value if it is the final evaluated value of a text interpolation -->
<p>{{ user.age}} </p>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
const refString = ref("abc");
// Need use .value to access/mutate ref value here
const mutateRef = (): void => {
refString.value = "def";
}
const user = {
age: ref(20)
}
const count = ref(0)
// Dont need .value if ref is property of reactive object
const state1 = reactive({count})
console.log(state1.count) // 0
// But need .value if ref is property of reactive array
const state2 = reactive([count])
console.log(state2[0].value) // 0
// But need .value if ref is property of reactive collection
const state3 = reactive(new Map([['count', count]]))
console.log(state3.get('count')!.value) // 0
</script>
ref
is more prefer than reactive
reactive
only takes object. ref
can hold any value typeconst reactiveNumber = reactive(0) // won't work
.value
may seem wordy as first, but it helps reminding us that we are dealing with reactivity.reactive
and lose reactivity without realizing what's happening. Because it doesn't have .value
to remind us// This is likely a reative value using ref
someRef.value = 'New value'
// Is this going to update reactively or just a simple object
// It's impossible to know just from looking at this line
someObject.property = 'New value'
ref
from a composition function, you can destruct it safely. Otherwise we have to use toRefs
const useData = () => {
const firstName = ref('John');
const lastName = ref('Doe');
const age = ref(30);
return { firstName, lastName, age };
};
// In component
...
const { firstName, lastName, age } = useData();
template refs
. We can use template reactive
, but it requires a bit of extra syntax using function ref
<template>
<div>
<h1 :ref="(el) => {heading.element = el}">
Heading
</h1>
</div>
</template>
<script setup>
const heading = reactive(null)
</script>
ref
cannot be avoided since computed
returns a ref, and we also have template ref
.toRefs()
or toRef()
to safely destruct objects and maintain reactivity from props
or composable functionUpvotes: 4
Reputation: 13696
reactive()
only takes objects, NOT JS primitives (String, Boolean, Number, BigInt, Symbol, null, undefined)ref()
is calling reactive()
behind the scenesreactive()
works for objects and ref()
calls reactive()
, objects work for bothref()
has a .value
property for reassigning, reactive()
does not have this and therefore CANNOT be reassignedref()
when..
'string'
, true
, 23
, etc)reactive()
when..
ref()
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-CaseYou'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-CaseA 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);
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://vuejs.org/guide/extras/composition-api-faq.html#why-composition-api
Upvotes: 551
Reputation: 381
ref
object takes an inner value and returns a reactive and mutable object. usually used for primitive type single variables such as String, Boolean, Number, etc.
reactive
is a wrapper object that takes an object and returns a reactive proxy of the original object. usually used for dictionary-structured types such as JS Object.
You can learn more about ref vs reactive in this article: https://dev.to/hirajatamil/must-know-ref-vs-reactive-differences-in-vue-3-composition-api-3bp4
Upvotes: 0
Reputation: 27719
Other answers already show the differences between the two
reactive
: Create a reactive state. Returns a reactive proxy of the object:
import { reactive } from 'vue'
const reactiveObj = reactive({ count: 0 })
reactiveObj.count++
With Options API we used to keep reactive state in data()
. With Composition API we can achieve the same with reactive
API. So far, so good, but...
Why do we need
ref
???
Simply because reactive
has limitations such as:
const state = reactive({ count: 0 })
// the function receives a plain number and
// won't be able to track changes to state.count
callSomeFunction(state.count)
const state = reactive({ count: 0 })
let { count } = state
// does not affect original state
count++
let state = reactive({ count: 0 })
// this won't work!
state = reactive({ count: 1 })
So
ref
, was provided by Vue to address the limitations ofreactive
.
ref()
takes the argument and returns it wrapped within a ref object with a .value property:
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
Refs can:
const objectRef = ref({ count: 0 })
// this works reactively
objectRef.value = { count: 1 }
const obj = {
foo: ref(1),
bar: ref(2)
}
// the function receives a ref
// it needs to access the value via .value but it
// will retain the reactivity connection
callSomeFunction(obj.foo)
// still reactive
const { foo, bar } = obj
Should I always use
ref
?
Personal opinion follows
Most devs who have tried both, suggest using ref
from articles that I have read.
But personally, I think that ref
has the same limitation as reactive
if not used correctly and you can easily fall into "Reactivity loss" issues.
ref
has also some behaviors like:
reactive
Also having to deal with .value
every time is a bit confusing, Vue knows that and there is an RFC - Reactivity Transform as of this time of writing that aims to provide a solution.
I hope you now have a better understanding of reactive
and ref
but I think is worth mentioning that there more APIs for reactive state that you should be aware of: readonly, shallowRef, shallowReactive, shallowReadonly, unref, and many more.
Upvotes: 26
Reputation: 300
ref / reactive both are been used to create reactive object where the changes been tracked.
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.
It takes a JavaScript object as a argument and returns Proxy based reactive copy of the object.
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
Upvotes: 3
Reputation: 10404
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.
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.
Upvotes: 29
Reputation: 107
Below you can see our example using Reactive References on the upper part, and below other alternative reactive syntax.
//reactivity with ref syntax
import { ref, computed } from vue
export default {
setup() {
const capacity = ref(4)
const members = ref(["Tim", "John", "Andr"])
const simpleComputed = computed(() => {
return capacity.value - members.value.length
})
return { capacity, members, simpleComputed }
}
}
//reactivity with reactive syntax
import { reactive, computed } from vue
export default {
setup() {
const event = reactive({
capacity: 4,
members: ["Tim", "John", "Andr"]
simpleComputed: computed(() => {
return event.capacity - event.capacity.length
}
})
return { event }
}
}
As it shows in the code above on the bottom part, I created a new event constant which takes a plain JavaScript object and returns a reactive object. This may look familiar to using the data option in our regular component syntax, where I also send in an object. However, as you can see above, I can also send in our computed properties into this object. You should also notice that when I use this syntax we no longer need to write .value when accessing properties. This is because I am simply accessing the object properties on the event object. You should also notice that we’re returning the entire event
Both syntaxes are valid for usage, and neither is deemed as best practice
Upvotes: 1