Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the process of vue3.x data response?

2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "what is the responsive process of vue3.x data". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

What is data response?

When using Vue from the beginning, a big difference for previous jq development is that it is almost unnecessary to manually manipulate the data state changes declared in dom,data and automatically re-render the relevant dom.

In other words, Vue knows which data state has changed and where the data needs to be modified accordingly.

Therefore, there are two key issues in implementing data responsiveness:

How do I know that the data has changed?

How do I know where the data needs to be modified after it changes?

For the first question, how to know that the data has changed? Vue3 used ES6's Proxy in an API Object.defineProperty Vue3 of ES5 before, which detects changes in the data to be detected, adding getter and setter, so that you can know when the data is read and modified.

The second question is how to know where to modify the data after the change. Vue collects dependencies related to each data. The dependency here is actually an object that stores the old value of the data and the functions that need to be executed after the data changes. Each responsive data change will traverse each dependency corresponding to the notification. After receiving the notification, the dependency will determine whether the new and old values have changed, and if so, execute a callback function to respond to the data change (such as modifying dom).

A general process of data response

In the responsive part of vue3.0, the core file we need to find is in the src under runtime-core in the packages of the vue3.0 source code; the line we are studying today goes along the line of render.

Return {render, hydrate, createApp: createAppAPI (render, hydrate)}

Find the render function under this file, as shown below; the function of this function is to render and pass the vnode into the specified container

Const render: RootRenderFunction = (vnode, container) = > {if (vnode = = null) {if (container._vnode) {unmount (container._vnode, null, null, true)}} else {patch (container._vnode | | null, vnode, container)} flushPostFlushCbs () container._vnode = vnode}

Check the patch method. If initialized, you will use else if (shapeFlag & ShapeFlags.COMPONENT).

Const patch: PatchFn = (N1, N2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, optimized = false) = > {/ / patching & not same type, unmount old tree if (N1 &! isSameVNodeType (N1, N2)) {anchor = getNextHostNode (N1) unmount (N1, parentComponent, parentSuspense) True) N1 = null} if (n2.patchFlag = PatchFlags.BAIL) {optimized = false n2.dynamicChildren = null} const {type, ref, shapeFlag} = N2 switch (type) {case Text: processText (N1, N2, container, anchor) break case Comment: processCommentNode (N1, N2, container) Anchor) break case Static: if (N1 = = null) {mountStaticNode (N2, container, anchor, isSVG)} else if (_ _ DEV__) {patchStaticNode (N1, N2, container, isSVG)} break case Fragment: processFragment (N1, N2, container, anchor, parentComponent ParentSuspense, isSVG, optimized) break default: if (shapeFlag & ShapeFlags.ELEMENT) {processElement (N1, N2, container, anchor, parentComponent, parentSuspense, isSVG Optimized)} else if (shapeFlag & ShapeFlags.COMPONENT) {/ / initialize this processComponent (N1, N2, container, anchor, parentComponent, parentSuspense, isSVG) Optimized)} else if (shapeFlag & ShapeFlags.TELEPORT) { (type as typeof TeleportImpl) .process (N1 as TeleportVNode, N2 as TeleportVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals)} else if (_ _ FEATURE_SUSPENSE__ & & shapeFlag & ShapeFlags.SUSPENSE) { (type as typeof SuspenseImpl) .process (N1, N2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals)} else if (_ _ DEV__) {warn ('Invalid VNode type:', type `(${typeof type})`)} / / set ref if (ref! = null & & parentComponent) {setRef (ref, N1 & & n1.ref, parentComponent, parentSuspense, N2)}}

Next, take a look at the processComponent method, and then go to the familiar mountComponent

Const processComponent = (N1: VNode | null, N2: VNode, container: RendererElement, anchor: RendererNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, optimized: boolean) = > {if (N1 = = null) {if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) { Activate (N2, container, anchor, isSVG, optimized)} else {/ / initialize the mount process mountComponent (N2, container, anchor, parentComponent, parentSuspense, isSVG) Optimized)}} else {updateComponent (N1, N2, optimized)}}

Enter the mountComponent method, where the more important instance is for creating component instances, and setupComponent is for installing components; it is used for option processing; setupRenderEffec is used to create side effects of rendering functions and is used when relying on collection.

Const mountComponent: MountComponentFn = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) = > {/ / create component instance const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance (initialVNode, parentComponent) ParentSuspense)) if (_ _ DEV__ & & instance.type.__hmrId) {registerHMR (instance)} if (_ _ DEV__) {pushWarningContext (initialVNode) startMeasure (instance, `mount`)} / / inject renderer internals for keepAlive if (isKeepAlive (initialVNode)) { (instance.ctx as KeepAliveContext) .renderer = internals} / / resolve props and slots for setup context if (_ _ DEV__) {startMeasure (instance, `init`)} / / install the component: option to handle setupComponent (instance) if (_ _ DEV__) {endMeasure (instance, `init`)} / / setup () is async. This component relies on async logic to be resolved / / before proceeding if (_ _ FEATURE_SUSPENSE__ & & instance.asyncDep) {parentSuspense & & parentSuspense.registerDep (instance, setupRenderEffect) / / Give it a placeholder if this is not hydration / / TODO handle self-defined fallback if (! initialVNode.el) {const placeholder = (instance.subTree = createVNode (Comment)) processCommentNode (null, placeholder, container! Anchor)} return} / / build rendering function side effects: dependency collection setupRenderEffect (instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized) if (_ _ DEV__) {popWarningContext () endMeasure (instance, `mount`)}}

Go into the setupComponent function and look at the internal logic of the setupComponent function, where there is the initialization of the property slot; here you can see the setupStatefulComponent method, which is used to deal with response.

Export function setupComponent (instance: ComponentInternalInstance, isSSR = false) {isInSSRComponentSetup = isSSR const {props, children, shapeFlag} = instance.vnode const isStateful = shapeFlag & ShapeFlags.STATEFUL_COMPONENT initProps (instance, props, isStateful, isSSR) initSlots (instance, children) const setupResult = isStateful? SetupStatefulComponent (instance, isSSR): undefined isInSSRComponentSetup = false return setupResult}

Enter the method setupStatefulComponent, where const Component = instance.type as ComponentOptions is used for component configuration. Where instance.proxy = new Proxy (instance.ctx, PublicInstanceProxyHandlers) is used for proxy, data,$ and so on are handled here.

Function setupStatefulComponent (instance: ComponentInternalInstance, isSSR: boolean) {/ / component configuration const Component = instance.type as ComponentOptions if (_ _ DEV__) {if (Component.name) {validateComponentName (Component.name, instance.appContext.config)} if (Component.components) {const names = Object.keys (Component.components) for (let I = 0; I

< names.length; i++) { validateComponentName(names[i], instance.appContext.config) } } if (Component.directives) { const names = Object.keys(Component.directives) for (let i = 0; i < names.length; i++) { validateDirectiveName(names[i]) } } } // 0. create render proxy property access cache instance.accessCache = {} // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers) if (__DEV__) { exposePropsOnRenderContext(instance) } // 2. call setup() const { setup } = Component if (setup) { const setupContext = (instance.setupContext = setup.length >

1? CreateSetupContext (instance): null) currentInstance = instance pauseTracking () const setupResult = callWithErrorHandling (setup, instance, ErrorCodes.SETUP_FUNCTION, [_ _ DEV__? ShallowReadonly (instance.props): instance.props, setupContext]) resetTracking () currentInstance = null if (isPromise (setupResult)) {if (isSSR) {/ / return the promise so server-renderer can wait on it return setupResult.then ((resolvedResult: unknown) = > {handleSetupResult (instance, resolvedResult, isSSR)})} else if (_ FEATURE_SUSPENSE__) {/ / async setup returned Promise. / / bail here and wait for re-entry. Instance.asyncDep = setupResult} else if (_ _ DEV__) {warn (`setup () returned a Promise, but the version of Vue you are using `+ `does not support it yet.`)} else {handleSetupResult (instance, setupResult, isSSR)}} else {/ / transaction options such as finishComponentSetup (instance, isSSR)}}

Since there is no setup in our case, we will execute finishComponentSetup (instance, isSSR) to deal with things related to optional api. When you go into the function and look at the code logic, you will see the following code, which is used to deal with optional API-related things to support the version of vue2.x.

/ / support for 2.x options / / support option API if (_ _ FEATURE_OPTIONS_API__) {currentInstance = instance applyOptions (instance, Component) currentInstance = null}

Go into the applyOptions method; scroll down and you will see these lines of comments that clearly explain the priority of the various options in vue2.x, including props, inject, methods, data, and so on.

/ / options initialization order (to be consistent with Vue 2): / /-props (already done outside of this function) / /-inject / /-methods / /-data (deferred since it relies on `this` access) / /-computed / /-watch (deferred since it relies on `this` access)

If you look further down, you'll see these lines of code, which we're not using in a mixed form, so this line of code, which involves data correspondence, is all in the resolveData method.

When you enter resolveData, you can see const data = dataFn.call (publicThis, publicThis). This line of code is used to get the data object. Instance.data = reactive (data) this line of code is used for responsive processing of data. The core of this is reactive, which is used to do responsive processing. No matter the optional api or setup, the final method is the reactive method, which is used to do responsive processing.

Function resolveData (instance: ComponentInternalInstance, dataFn: DataFn, publicThis: ComponentPublicInstance) {if (_ _ DEV__ & &! isFunction (dataFn)) {warn (`The data option must be a function. `+` Plain object usage is no longer supportd.`)} / / get the data object const data = dataFn.call (publicThis, publicThis) if (_ _ DEV__ & & isPromise (data)) {warn (`data () returned a Promise-note data () cannot be async If you `+ `intend to perform data fetching before component renders, use` + `async setup () + .`} if (! isObject (data)) {_ _ DEV__ & & warn (`data () should return an object.`)} else if (instance.data = EMPTY_OBJ) {/ / a pair of data do responsive processing instance.data = reactive (data)} else {/ / existing data: this is a mixin or extends. Extend (instance.data, data)}}

Go into the reactive and observe the code logic; the createReactiveObject is used to process the data. Among them, target is the ultimate thing to be transformed.

Return createReactiveObject (target, false, mutableHandlers, mutableCollectionHandlers)

There are some get, set, deleteProperty and other methods in mutableHandlers. MutableCollectionHandlers creates operations such as dependency collection.

Comparison of vue2.x data response and 3.x response

At this point, let's review how vue2.x handles responsiveness. From this point of view, this set of treatment is not friendly. All key of recursive objects are needed in Vue2.x, which is slow. Array response requires additional implementation. And add or delete properties cannot be monitored, you need to use a special api. Now, a direct new proxy directly solves all the problems. At the same time, the previous set of methods do not know Map,Set, Class and other data structures.

General flow chart

Then let's sort out the order of the process to the responsive type.

Implement dependency collection

In the process of implementing responsiveness, dependency collection is closely related to it, in which the setupRenderEffect function uses the effect function to do dependency collection. Inside the setupRenderEffect function, there is this function in the above code. Without going into detail here, let's move on. If you go inside the function, you will see the following code. Effect can establish a dependency: between the callback function of effect and the response data; effect is equivalent to dep in vue2, and then there is no watcher in vue3.

Instance.update = effect (function componentEffect () {if (! instance.isMounted) {let vnodeHook: VNodeHook | null | undefined const {el, props} = initialVNode const {bm, m, parent} = instance

Looking further down, you will see the following code, where subTree is the current component vnode, where the renderComponentRoot method is used to implement the root of the rendering component.

Const subTree = (instance.subTree = renderComponentRoot (instance)) "what is the process of vue3.x data response" is introduced here, thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report