


Detailed explanation of the difference between reactive and ref in vue3 (source code analysis)
What is the difference between reactive and ref in
vue? The following article will take you deep into the source code to thoroughly understand the difference between reactive and ref in vue3. I hope it will be helpful to you!
In the daily development of vue3, I found that many people use a shuttle based on their own habitsreactive
orref
, although this can meet the requirements, if this is the case, why do we need to design another ref
when we already have reactive
? What are the actual application scenarios and differences between the two?
And regarding the underlying logic of ref
, some people say that the underlying logic of ref
is still reactive
. Some people say that the bottom layer of ref
is class
, and value
is just an attribute of class
. Which of the two statements is correct? Woolen cloth? Is there any basis for this?
With this question, we will go deep into the source code this time and thoroughly understand the difference between reactive
and ref
in vue3. (Learning video sharing: vue video tutorial)
If you don’t want to see the source code, you can just scroll to the back and read the summary
reactive
Source code address: packages/reactivity/reactive.ts
First let’s take a look at the target used in vue3
ReactiveFlags
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">// 标记目标对象 target 类型的 ReactiveFlags
export const enum ReactiveFlags {
SKIP = '__v_skip',
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
RAW = '__v_raw'
}
export interface Target {
[ReactiveFlags.SKIP]?: boolean // 不做响应式处理的数据
[ReactiveFlags.IS_REACTIVE]?: boolean // target 是否是响应式
[ReactiveFlags.IS_READONLY]?: boolean // target 是否是只读
[ReactiveFlags.RAW]?: any // 表示proxy 对应的源数据, target 已经是 proxy 对象时会有该属性
}</pre><div class="contentsignin">Copy after login</div></div>
reactive
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The reactive
function receives a target
object. If the target
object is read-only, it will return the object directly.
If it is not read-only, it will pass directly. createReactiveObject
Createobserve
Object
createReactiveObject
Don’t be afraid of the long look, Post the complete code of createReactiveObject
first, let’s read it in sections
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
First we see that createReactiveObject
receives five parameters
1 2 3 4 5 |
|
target Target object
isReadonly Whether it is read-only
baseHandlers Basic type handlers Processing arrays, objects
collectionHandlers Processing set, map, weakSet, weakMap
proxyMap WeakMap data structure stores side effect functions
Here mainly through ReactiveFlags. RAW
and ReactiveFlags.IS_REACTIVE
determine whether it is responsive data. If so, the object will be returned directly
1 2 3 4 5 6 |
|
For those that are already Proxy
, then Directly take out the Proxy object from the WeakMap
data structure and return
1 2 3 4 |
|
Here is a check to see if the type of the current target
is Object
, Array
, Map
, Set
, WeakMap
, WeakSet
, if none, go directly Return the object without performing responsive processing
1 2 3 4 5 |
|
Verification type logic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
After all pre-verifications are completed, you can useproxy
Agenttarget
Object
A ternary operator
is used here to execute different processing logic# through
TargetType.COLLECTION
- ##(set, map, weakSet, weakMap) Use
- collectionHandlers
- baseHandlers
1 2 3 4 5 6 7 8 9 |
|
Now the execution logic of
createReactiveObject is very clear
proxy in
createReactiveObject How to proxy
target? Here we use
baseHandlers as an example and go deep inside
baseHandlers to see
baseHandlers
packages/reactivity/baseHandlers.ts
reactive.ts we can see that a total of four handlers have been introduced
1 2 3 4 5 6 |
|
- mutableHandlers
Variable processing
- readonlyHandlers
Read-only processing
- shallowReactiveHandlers
Shallow observation Processing (only observe the first-level properties of the target object)
- shallowReadonlyHandlers
Shallow observation && read-only
mutableHandlers as an example
1 2 3 4 5 6 7 8 9 10 11 12 |
|
get and
set here correspond to
createGetter() and
createSetter()# respectively.
- ##createGetter()
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
|
It looks long, but in the end it is
track()Dependency collection
track()There are too many dependency collection contents, and
trigger()
triggers updates together, so I will write a separate article Article
- createSetter()
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 31 32 33 34 35 36 37 38 |
|
与ref
的区别就是在调用createRef()
时第二个值传的是true
1 2 3 |
|
看一下官方文档上对shallowRef
的解释
createRef
通过isRef()
判断是否是ref
数据,是则直接返回该数据,不是则通过new RefImpl
创建ref数据
在创建时会传两个值一个是rawValue
(原始值),一个是shallow
(是否是浅观察),具体使用场景可看上面ref
和shallowRef
的介绍
1 2 3 4 5 6 7 |
|
isRef()
通过__v_isRef
只读属性判断是否是ref数据,此属性会在RefImpl
创建ref数据时添加
1 2 3 |
|
RefImpl
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 |
|
根据RefImpl
我们可以看到ref
的底层逻辑,如果是对象确实会使用reactive
进行处理,并且ref
的创建使用的也是RefImpl
class实例,value只是RefImpl
的属性
在我们访问
和设置
ref
的value值时,也分别是通过get
和set
拦截进行依赖收集
和派发更新
的
toReactive
我们来看一下toReactive()
这个方法,在RefImpl
中创建ref
数据时会调用toReactive()
方法,这里会先判断传进来的值是不是对象,如果是就用reactive()
包裹,否则就返回其本身
1 2 |
|
trackRefValue
ref的依赖收集方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
triggerRefValue
ref的派发更新方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
总结
看完reactive
和ref
源码,相信对本文一开始的几个问题也都有了答案,这里也总结了几个问题:
- 问:ref的底层逻辑是什么,具体是如何实现的
答:ref底层会通过 new RefImpl()
来创造ref数据,在new RefImpl()
会首先给数据添加__v_isRef
只读属性用来标识ref
数据。而后判断传入的值是否是对象,如果是对象则使用toReactive()
处理成reactive
,并将值赋给RefImpl()
的value
属性上。在访问
和设置
ref数据的value
时会分别触发依赖收集
和派发更新
流程。
- 问:ref底层是否会使用
reactive
处理数据
答:RefImpl中非浅观察会调用toReactive()
方法处理数据,toReactive()
中会先判断传入的值是不是一个对象,如果是对象则使用reactive
进行处理,不是则直接返回值本身。
- 问:为什么已经有了
reactive
还需要在设计一个ref
呢?
答: 因为vue3响应式方案使用的是proxy
,而proxy
的代理目标必须是非原始值,没有任何方式能去拦截对原始值
的操作,所以就需要一层对象作为包裹,间接实现原始值的响应式方案。
- 问:为什么
ref
数据必须要有个value
属性,访问ref数据必须要通过.value
的方式呢?
答:这是因为要解决响应式丢失的问题
,举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
可以看到,在现在的newObj
对象下,具有与obj
对象同名的属性,而且每个属性的值都是一个对象,例如foo 属性的值是:
1 2 3 4 5 |
|
该对象有一个访问器属性value
,当读取value的值时,最终读取的是响应式数据obj下的同名属性值
。也就是说,当在副作用函数内读取newObj.foo
时,等价于间接读取了obj.foo
的值。这样响应式数据就能够与副作用函数建立响应联系
(Learning video sharing: web front-end development, Basic programming video)
The above is the detailed content of Detailed explanation of the difference between reactive and ref in vue3 (source code analysis). For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



tinymce is a fully functional rich text editor plug-in, but introducing tinymce into vue is not as smooth as other Vue rich text plug-ins. tinymce itself is not suitable for Vue, and @tinymce/tinymce-vue needs to be introduced, and It is a foreign rich text plug-in and has not passed the Chinese version. You need to download the translation package from its official website (you may need to bypass the firewall). 1. Install related dependencies npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2. Download the Chinese package 3. Introduce the skin and Chinese package. Create a new tinymce folder in the project public folder and download the

vue3+vite:src uses require to dynamically import images and error reports and solutions. vue3+vite dynamically imports multiple images. If vue3 is using typescript development, require will introduce image errors. requireisnotdefined cannot be used like vue2 such as imgUrl:require(' .../assets/test.png') is imported because typescript does not support require, so import is used. Here is how to solve it: use awaitimport

To achieve partial refresh of the page, we only need to implement the re-rendering of the local component (dom). In Vue, the easiest way to achieve this effect is to use the v-if directive. In Vue2, in addition to using the v-if instruction to re-render the local dom, we can also create a new blank component. When we need to refresh the local page, jump to this blank component page, and then jump back in the beforeRouteEnter guard in the blank component. original page. As shown in the figure below, how to click the refresh button in Vue3.X to reload the DOM within the red box and display the corresponding loading status. Since the guard in the component in the scriptsetup syntax in Vue3.X only has o

Vue implements the blog front-end and needs to implement markdown parsing. If there is code, it needs to implement code highlighting. There are many markdown parsing libraries for Vue, such as markdown-it, vue-markdown-loader, marked, vue-markdown, etc. These libraries are all very similar. Marked is used here, and highlight.js is used as the code highlighting library. The specific implementation steps are as follows: 1. Install dependent libraries. Open the command window under the vue project and enter the following command npminstallmarked-save//marked to convert markdown into htmlnpmins

The final effect is to install the VueCropper component yarnaddvue-cropper@next. The above installation value is for Vue3. If it is Vue2 or you want to use other methods to reference, please visit its official npm address: official tutorial. It is also very simple to reference and use it in a component. You only need to introduce the corresponding component and its style file. I do not reference it globally here, but only introduce import{userInfoByRequest}from'../js/api' in my component file. import{VueCropper}from'vue-cropper&

Preface Whether it is vue or react, when we encounter multiple repeated codes, we will think about how to reuse these codes instead of filling a file with a bunch of redundant codes. In fact, both vue and react can achieve reuse by extracting components, but if you encounter some small code fragments and you don’t want to extract another file, in comparison, react can be used in the same Declare the corresponding widget in the file, or implement it through renderfunction, such as: constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

vue3+ts+axios+pinia realizes senseless refresh 1. First download aiXos and pinianpmipinia in the project--savenpminstallaxios--save2. Encapsulate axios request-----Download js-cookienpmiJS-cookie-s//Introduce aixosimporttype{AxiosRequestConfig ,AxiosResponse}from"axios";importaxiosfrom'axios';import{ElMess

Using Vue to build custom elements WebComponents is a collective name for a set of web native APIs that allow developers to create reusable custom elements (customelements). The main benefit of custom elements is that they can be used with any framework, even without one. They are ideal when you are targeting end users who may be using a different front-end technology stack, or when you want to decouple the final application from the implementation details of the components it uses. Vue and WebComponents are complementary technologies, and Vue provides excellent support for using and creating custom elements. You can integrate custom elements into existing Vue applications, or use Vue to build
