Problem
Suppose we have the formula for calculating the total amount based on the quantity and price of a product as follows:
1 2 3 4 | <span class="token keyword">let</span> price <span class="token operator">=</span> <span class="token number">5</span> <span class="token keyword">let</span> quantity <span class="token operator">=</span> <span class="token number">2</span> <span class="token keyword">let</span> total <span class="token operator">=</span> price <span class="token operator">*</span> quantity <span class="token comment">// = 10</span> |
If we change the price of the product
1 2 3 | price <span class="token operator">=</span> <span class="token number">20</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> total <span class="token punctuation">)</span> <span class="token comment">// 10</span> |
Now total
still 10. Because that’s how javascript
works.
So is there any way to make the value of this total
reactive
. That is, will its value change based on price
and quantity
? Let’s continue to read the article
The answer
I will put the total
calculation above in a function and call it a effect
1 2 3 4 | <span class="token keyword">const</span> <span class="token function-variable function">effect</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> total <span class="token operator">=</span> price <span class="token operator">*</span> quantity <span class="token punctuation">}</span> |
Thus, to solve the above problem, we will find a way to run this effect
function whenever price
and quantity
change.
And to do that, we will define price
and quantity
in an object
. Type as follows:
1 2 3 4 5 | <span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token punctuation">{</span> price <span class="token punctuation">:</span> <span class="token number">5</span> <span class="token punctuation">,</span> quantity <span class="token punctuation">:</span> <span class="token number">2</span> <span class="token punctuation">}</span> |
And our effect
will become
1 2 3 4 | <span class="token keyword">let</span> <span class="token function-variable function">effect</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> total <span class="token operator">=</span> state <span class="token punctuation">.</span> price <span class="token operator">*</span> state <span class="token punctuation">.</span> quantity <span class="token punctuation">}</span> |
Next we will loop through each property
in the state
object and use Object.defineProperty
to redefine the getter
and setter
for the state
as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 | Object <span class="token punctuation">.</span> <span class="token function">keys</span> <span class="token punctuation">(</span> state <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">forEach</span> <span class="token punctuation">(</span> key <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> internalValue <span class="token operator">=</span> state <span class="token punctuation">[</span> key <span class="token punctuation">]</span> <span class="token comment">// Phải khởi tạo biến này với let</span> Object <span class="token punctuation">.</span> <span class="token function">defineProperty</span> <span class="token punctuation">(</span> state <span class="token punctuation">,</span> key <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> internalValue <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token keyword">set</span> <span class="token punctuation">(</span> newValue <span class="token punctuation">)</span> <span class="token punctuation">{</span> internalValue <span class="token operator">=</span> newValue <span class="token punctuation">;</span> <span class="token function">effect</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// lúc thay đổi giá trị sẽ chạy lại effect</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> |
Thus, when we assign the value state.price = 10
for example, it will run the effect
function.
And so the total
is updated!
Furthermore, we can create a function that can be reused for other objects as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">const</span> <span class="token function-variable function">reactive</span> <span class="token operator">=</span> data <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> newData <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">...</span> data <span class="token punctuation">}</span> <span class="token punctuation">;</span> Object <span class="token punctuation">.</span> <span class="token function">keys</span> <span class="token punctuation">(</span> newData <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">forEach</span> <span class="token punctuation">(</span> key <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> internalValue <span class="token operator">=</span> newData <span class="token punctuation">[</span> key <span class="token punctuation">]</span> Object <span class="token punctuation">.</span> <span class="token function">defineProperty</span> <span class="token punctuation">(</span> newData <span class="token punctuation">,</span> key <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> internalValue <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token keyword">set</span> <span class="token punctuation">(</span> newValue <span class="token punctuation">)</span> <span class="token punctuation">{</span> internalValue <span class="token operator">=</span> newValue <span class="token punctuation">;</span> <span class="token function">effect</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 punctuation">)</span> <span class="token keyword">return</span> newData <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
And our state
will look like this:
1 2 3 4 5 | <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> price <span class="token punctuation">:</span> <span class="token number">5</span> <span class="token punctuation">,</span> quantity <span class="token punctuation">:</span> <span class="token number">2</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
OK, delicious.
Wait wait. Why haven’t you said anything about Proxy
?
Here!. With Proxy
we can redefine reactive
function in a more concise way:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">const</span> <span class="token function-variable function">reactive</span> <span class="token operator">=</span> data <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span> <span class="token punctuation">(</span> data <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">(</span> target <span class="token punctuation">,</span> key <span class="token punctuation">,</span> receiver <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> target <span class="token punctuation">[</span> key <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token keyword">set</span> <span class="token punctuation">(</span> target <span class="token punctuation">,</span> key <span class="token punctuation">,</span> value <span class="token punctuation">,</span> receiver <span class="token punctuation">)</span> <span class="token punctuation">{</span> target <span class="token punctuation">[</span> key <span class="token punctuation">]</span> <span class="token operator">=</span> value <span class="token punctuation">;</span> <span class="token function">effect</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> |
And if using Reflect
:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">const</span> <span class="token function-variable function">reactive</span> <span class="token operator">=</span> data <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span> <span class="token punctuation">(</span> data <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">(</span> target <span class="token punctuation">,</span> key <span class="token punctuation">,</span> receiver <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Reflect <span class="token punctuation">.</span> <span class="token keyword">get</span> <span class="token punctuation">(</span> <span class="token operator">...</span> arguments <span class="token punctuation">)</span> <span class="token comment">// arguments trong mỗi function đều có mn nhé :) </span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token keyword">set</span> <span class="token punctuation">(</span> target <span class="token punctuation">,</span> key <span class="token punctuation">,</span> value <span class="token punctuation">,</span> receiver <span class="token punctuation">)</span> <span class="token punctuation">{</span> Reflect <span class="token punctuation">.</span> <span class="token keyword">set</span> <span class="token punctuation">(</span> <span class="token operator">...</span> arguments <span class="token punctuation">)</span> <span class="token function">effect</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> |
Now if we initialize the state
with reactive
, we will get a Proxy
as follows:
OK, genuine.
Actually, Proxy
not only makes our code more concise, but also helps in dealing with reactive
arrays, …
In this article, I just introduced a brief overview of reactive
. We can see that the actual effect
must also be saved and calculated in some way so that we can use multiple effect
at the same time.
The article came here, I don’t really understand it. You can find out more carefully in the link below. Good luck
References
https://www.vuemastery.com/courses/vue-3-reactivity/vue3-reactivity https://www.vuemastery.com/courses/advanced-components/build-a-reactivity-system