In Vue 3, there are two Reactivity APIs that are confusing for newbies to use: ref and reactive . In this article, I will show you how to use the above 2 APIs, with some comparisons with Vue 2 for those who have just moved from Vue 2 to Vue 3.
Ref
Simple example when changing a reactive state with Vue 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> Count <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> count <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> button @click <span class="token operator">=</span> <span class="token string">"increaseCount"</span> <span class="token operator">></span> Increase Count <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> count <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> methods <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">increaseCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> count <span class="token operator">++</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
Similar functionality but using ref() in Vue 3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> Count <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> count <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> button @click <span class="token operator">=</span> <span class="token string">"increaseCount"</span> <span class="token operator">></span> Increase Count <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vue"</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">setup</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Tạo 1 reactive state count = 0</span> <span class="token comment">// (count ở đây là một Proxy object chứ không phải number)</span> <span class="token keyword">const</span> count <span class="token operator">=</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">increaseCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Tăng giá trị của count bằng cách cập nhật giá trị thuộc tính value</span> count <span class="token punctuation">.</span> value <span class="token operator">++</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> count <span class="token punctuation">,</span> increaseCount <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
To better understand how ref() works, you should learn more about Proxy in Javascript .
Some notes about ref():
- We can save any data to the ref object as well.
- Ref object is mutable , when you need to change the value, you can change its value property directly. However, when using the ref object in the template, we don’t need the .value because it is automatically unwrapped .
Reactive
In most cases, we just need to use ref() . So what is reactive() used for?
reactive() works similar to ref() but it only accepts objects as arguments, not primitives (number, string, boolean). And we change the value of the reactive object by changing its properties (instead of changing the value property like ref ). The example above is rewritten with reactive() :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> Count <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> state <span class="token punctuation">.</span> count <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> button @click <span class="token operator">=</span> <span class="token string">"increaseCount"</span> <span class="token operator">></span> Increase Count <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vue"</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">setup</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Tạo 1 reactive state có thuộc tính count = 0</span> <span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token function">reactive</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> count <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">increaseCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Tăng giá trị của thuộc tính count</span> state <span class="token punctuation">.</span> count <span class="token operator">++</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> state <span class="token punctuation">,</span> increaseCount <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
In essence, ref() is a function to wrap reactive (inside ref() uses reactive() ), so in most cases we can use most of ref() for synchronization and save a lot of memory. , just pay attention when changing the value of the ref object through the value attribute. You can also use reactive when you want to create a centralized state to avoid creating many variables, for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token comment">// Dùng ref()</span> <span class="token keyword">const</span> isLoading <span class="token operator">=</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> isError <span class="token operator">=</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Robin"</span> <span class="token punctuation">,</span> role <span class="token operator">:</span> <span class="token string">"Admin"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Dùng reactive()</span> <span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token function">reactive</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> isLoading <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> isError <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> user <span class="token operator">:</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Robin"</span> <span class="token punctuation">,</span> role <span class="token operator">:</span> <span class="token string">"Admin"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Note that when using reactive we can only pass an object and when updating, we will update the properties of that object, not using direct assignment to the reactive object . For example the following is false:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> User name <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> user <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> User role <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> user <span class="token punctuation">.</span> role <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> button @click <span class="token operator">=</span> <span class="token string">"updateUser"</span> <span class="token operator">></span> Update <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">import</span> <span class="token punctuation">{</span> reactive <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vue"</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">setup</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Tạo 1 reactive object user</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">reactive</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Robin"</span> <span class="token punctuation">,</span> role <span class="token operator">:</span> <span class="token string">"Admin"</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">updateUser</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Ví dụ dữ liệu mới lấy từ form, api, ... sau đó update trực tiếp bằng phép gán</span> <span class="token comment">// Code sai</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Huy"</span> <span class="token punctuation">,</span> role <span class="token operator">:</span> <span class="token string">"Staff"</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> user <span class="token punctuation">,</span> updateUser <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
In line 20 of the above example, the code is wrong because we assign a value to the user variable to a new object. If at the time of declaration using const
, it will always report an error, and if using let
, the code will be syntactically correct, but when the button is pressed, the interface will not update because the user variable is no longer a reactive object , just a normal object. It can be fixed by updating the properties one by one:
1 2 3 | user <span class="token punctuation">.</span> name <span class="token operator">=</span> <span class="token string">"Huy"</span> <span class="token punctuation">;</span> user <span class="token punctuation">.</span> role <span class="token operator">=</span> <span class="token string">"Staff"</span> <span class="token punctuation">;</span> |
Or use ref()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> User name <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> user <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> h1 <span class="token operator">></span> User role <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> user <span class="token punctuation">.</span> role <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> button @click <span class="token operator">=</span> <span class="token string">"updateUser"</span> <span class="token operator">></span> Update <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vue"</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">setup</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Tạo 1 ref object user</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Robin"</span> <span class="token punctuation">,</span> role <span class="token operator">:</span> <span class="token string">"Admin"</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">updateUser</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Cập nhật ref object qua thuộc tính value</span> user <span class="token punctuation">.</span> value <span class="token operator">=</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Huy"</span> <span class="token punctuation">,</span> role <span class="token operator">:</span> <span class="token string">"Staff"</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> user <span class="token punctuation">,</span> updateUser <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
Source: https://huydq.dev .