阿里云主机折上折
  • 微信号
Current Site:Index > The processing method for nested response objects

The processing method for nested response objects

Author:Chuan Chen 阅读数:57874人阅读 分类: Vue.js

Handling of Nested Reactive Objects

Vue 3's reactivity system is based on Proxy, and its approach to handling nested objects differs significantly from Vue 2. When encountering nested objects, Vue 3 recursively converts the entire object tree into reactive proxies, providing more granular dependency tracking.

Basic Handling Mechanism

When creating a reactive object with the reactive() function, Vue 3 deeply proxies nested objects. For example:

const obj = reactive({
  nested: {
    count: 0
  },
  array: [{ value: 1 }]
})

In this example, not only is obj itself reactive, but obj.nested and obj.array[0] are also automatically converted into reactive objects. This processing occurs upon first access to the property, using a lazy proxy strategy:

// Nested objects are proxied only upon first access
console.log(isReactive(obj.nested)) // true
console.log(isReactive(obj.array[0])) // true

Implementation Principle of Recursive Proxying

In baseHandlers.ts, the Proxy's get interceptor handles nested objects as follows:

function createGetter(isReadonly = false) {
  return function get(target: object, key: string | symbol) {
    const res = Reflect.get(target, key)
    // If the retrieved value is an object, recursively call reactive
    if (typeof res === 'object' && res !== null) {
      return isReadonly ? readonly(res) : reactive(res)
    }
    return res
  }
}

This design ensures that no matter how deep the object nesting goes, each access returns the corresponding reactive proxy.

Special Handling for Arrays

For array types, Vue 3 includes specific optimizations. When modifying array elements, reactivity is correctly triggered:

const list = reactive([{ value: 1 }, { value: 2 }])

// Modifying nested objects triggers reactivity
list[0].value = 3 

// Directly setting array elements also works
list[0] = { value: 4 } 

The logic for handling arrays is primarily implemented in collectionHandlers.ts, where array mutation methods (such as push, pop, etc.) are overridden to ensure reactivity.

Avoiding Duplicate Proxying

Vue 3 uses a WeakMap to cache already proxied objects, preventing duplicate proxying:

const reactiveMap = new WeakMap()

function reactive(target) {
  // If already proxied, return the cached version
  const existingProxy = reactiveMap.get(target)
  if (existingProxy) return existingProxy
  
  // Create a new proxy
  const proxy = new Proxy(target, baseHandlers)
  reactiveMap.set(target, proxy)
  return proxy
}

This caching mechanism ensures that the same original object always returns the same proxy instance.

Performance Optimization Strategies

Deep reactive conversion can incur performance overhead. Vue 3 provides two optimization methods:

  1. Shallow Reactivity: Use shallowReactive to proxy only the first-level properties
const shallow = shallowReactive({
  nested: { count: 0 } // nested will not be automatically proxied
})
  1. Manual Non-Reactive Marking: Use markRaw to skip proxying
const rawObj = markRaw({ count: 0 })
const obj = reactive({ nested: rawObj }) // nested remains a raw object

Comparison with Vue 2

Vue 2 uses Object.defineProperty to implement reactivity, requiring recursive conversion of the entire object upfront:

// Vue 2 approach - recursively converts during initialization
new Vue({
  data() {
    return { nested: { count: 0 } } // nested is converted immediately
  }
})

In contrast, Vue 3's lazy proxying strategy offers advantages in performance and memory usage, especially for large, deeply nested objects.

Practical Application Scenarios

Consider a form component handling nested data structures:

const form = reactive({
  user: {
    name: '',
    address: {
      city: '',
      street: ''
    }
  },
  preferences: {
    notifications: true,
    theme: 'light'
  }
})

// Deep properties can be directly bound in templates
watch(() => form.user.address.city, (newVal) => {
  console.log('City changed:', newVal)
})

This nested reactive handling makes complex state management more intuitive, eliminating the need to manually handle reactivity at each level.

Edge Case Handling

Certain special scenarios require attention:

  1. Prototype Chain Properties: Do not trigger reactivity
const parent = { count: 1 }
const child = reactive(Object.create(parent))
console.log(child.count) // 1, but modifying parent.count will not trigger reactivity
  1. Symbol Properties: Proxied by default
const sym = Symbol()
const obj = reactive({ [sym]: 'value' })
console.log(obj[sym]) // Reactive access
  1. Circular References: Automatically handled
const obj = {}
obj.self = obj
const reactiveObj = reactive(obj) // No stack overflow

Reactive Object Identity

Since each access to a nested object returns the same proxy instance, strict equality checks can be used:

const obj = reactive({ nested: {} })
console.log(obj.nested === obj.nested) // true

This feature plays a key role in dependency collection and component update optimization.

Integration with Refs

When a nested object contains a ref, Vue 3 automatically unwraps it:

const count = ref(0)
const obj = reactive({ count })

console.log(obj.count) // 0, no .value needed
obj.count++ // Direct modification

This automatic unwrapping mechanism allows refs and reactive objects to be used together without conflict.

Key Source Code Locations

The main implementation is distributed across several core files:

  1. packages/reactivity/src/reactive.ts - Core proxying logic
  2. packages/reactivity/src/baseHandlers.ts - Basic proxy handlers
  3. packages/reactivity/src/collectionHandlers.ts - Collection type handlers

The createReactiveObject function is the entry point for creating reactive objects, handling caching, read-only proxies, and other logic.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.