Hone logo
Hone
Problems

Implementing a Shallow Reactive Reference in Vue (TypeScript)

Vue's reactivity system is powerful, but sometimes you only want a shallow level of reactivity for certain data structures. This challenge asks you to implement a custom shallowRef function that mimics Vue's built-in shallowRef, providing reactivity only for the top-level properties of an object, while leaving nested objects and arrays non-reactive. This is useful for performance optimization when you know you won't be modifying nested structures directly.

Problem Description

You need to create a function called shallowRef that takes a value as input and returns an object with a .value property. This .value property should be reactive, meaning changes to it trigger updates in components that depend on it. However, any properties added to or modified within the .value property should not become reactive. The function should be written in TypeScript and leverage Vue's reactivity API.

Key Requirements:

  • The function must accept any type of value as input.
  • The returned object must have a .value property.
  • Changes to the .value property should trigger reactivity updates.
  • Modifications to properties within .value should not trigger reactivity.
  • Adding new properties to .value should not trigger reactivity.

Expected Behavior:

When a component uses shallowRef, changes to the top-level .value property should cause the component to re-render. However, if the component attempts to modify a nested property within .value, no reactivity should be triggered, and the component should not re-render.

Edge Cases to Consider:

  • The initial value passed to shallowRef can be any data type (object, array, primitive).
  • The .value property can be reassigned to a completely new value.
  • The .value property can be an object or array containing other objects or arrays.

Examples

Example 1:

Input: shallowRef({ count: 1, data: { name: 'Alice' } })
Output: { value: { count: 1, data: { name: 'Alice' } } }
Explanation: The `count` property is reactive. Changing `shallowRef.value.count = 2` will trigger a re-render. However, changing `shallowRef.value.data.name = 'Bob'` will *not* trigger a re-render.

Example 2:

Input: shallowRef([1, 2, { a: 3 }])
Output: { value: [1, 2, { a: 3 }] }
Explanation: The array itself is reactive. Changing `shallowRef.value[0] = 4` will trigger a re-render. However, changing `shallowRef.value[2].a = 5` will *not* trigger a re-render.

Example 3: (Edge Case)

Input: shallowRef(123)
Output: { value: 123 }
Explanation: Even with a primitive value, the `.value` property should be reactive. Changing `shallowRef.value = 456` will trigger a re-render.

Constraints

  • The solution must be written in TypeScript.
  • The solution must use Vue's reactivity API (reactive, ref, markRaw). markRaw is particularly important here.
  • The solution should be relatively concise and readable.
  • The solution should not introduce any unnecessary dependencies.
  • Performance is not a primary concern for this challenge, but avoid obviously inefficient approaches.

Notes

Think about how Vue's reactivity system works and how you can leverage markRaw to prevent reactivity from propagating to nested properties. Consider the difference between creating a reactive object and simply assigning a value to a reactive property. The key is to make the .value property reactive, but prevent reactivity from "leaking" into its contents. Remember that shallowRef is designed for performance optimization, so avoid unnecessary reactivity.

Loading editor...
typescript