Hone logo
Hone
Problems

Reactive Dependency Tracker in Vue.js (TypeScript)

This challenge focuses on building a simplified reactive dependency tracker within a Vue.js context, using TypeScript for type safety. Reactive dependency tracking is a core concept in Vue.js, enabling automatic updates when data changes. By implementing a basic version, you'll gain a deeper understanding of how Vue's reactivity system works under the hood.

Problem Description

You are tasked with creating a ReactiveDependencyTracker class that monitors changes to a given value and notifies a list of registered dependencies whenever that value is updated. This tracker should be able to handle primitive types (string, number, boolean) and objects. The tracker should maintain a list of "dependencies" which are functions that should be called when the tracked value changes. The class should provide methods to:

  1. track(dependency: () => void): Registers a function (dependency) to be called when the tracked value changes.
  2. update(newValue: any): Updates the tracked value and executes all registered dependencies.
  3. getValue(): any: Returns the current tracked value.

The key requirement is that the update method should trigger all registered dependencies without directly passing the new value to them. Instead, the dependencies should be able to access the current value via the getValue() method. This simulates how Vue's reactivity system works, where components re-render based on the current state, not just the change itself.

Expected Behavior:

  • When track is called, the provided function is added to the internal list of dependencies.
  • When update is called, the tracked value is updated, and each registered dependency is invoked.
  • Dependencies should be invoked in the order they were registered.
  • getValue should return the most recently set value.

Edge Cases to Consider:

  • Handling updates to objects: While this challenge doesn't require deep reactivity, consider how the tracker handles object updates. A simple assignment is sufficient.
  • Multiple calls to track with the same dependency function: Ensure the dependency is only added once.
  • Calling update before track: Dependencies should not be invoked if none are registered.
  • Calling getValue before update: Should return the initial value (if provided during instantiation) or undefined.

Examples

Example 1:

Input:
tracker = new ReactiveDependencyTracker(10);
const dependency1 = () => console.log("Dependency 1: Value is now", tracker.getValue());
const dependency2 = () => console.log("Dependency 2: Value is now", tracker.getValue());

tracker.track(dependency1);
tracker.track(dependency2);
tracker.update(20);

Output:
Dependency 1: Value is now 20
Dependency 2: Value is now 20

Explanation:
The tracker is initialized with the value 10. Two dependencies are registered. When the value is updated to 20, both dependencies are invoked, each logging the current value (20).

Example 2:

Input:
tracker = new ReactiveDependencyTracker("hello");
const dependency1 = () => console.log("Dependency 1: Value is now", tracker.getValue());
tracker.track(dependency1);
tracker.update("world");
tracker.update("!");

Output:
Dependency 1: Value is now world
Dependency 1: Value is now !

Explanation:
The tracker is initialized with the value "hello". One dependency is registered. The value is updated twice, triggering the dependency each time.

Example 3:

Input:
tracker = new ReactiveDependencyTracker({});
const dependency1 = () => console.log("Dependency 1: Value is now", tracker.getValue());
tracker.track(dependency1);
tracker.update({name: "test"});

Output:
Dependency 1: Value is now [object Object]

Explanation:
The tracker is initialized with an empty object. One dependency is registered. The value is updated to a new object. The dependency is invoked, logging the current value (the object).

Constraints

  • The ReactiveDependencyTracker class must be implemented in TypeScript.
  • Dependencies must be invoked in the order they were registered.
  • The update method should not pass the new value directly to the dependencies. Dependencies should access the value via getValue().
  • The tracker should handle primitive types (string, number, boolean) and objects.
  • The tracker should not implement deep reactivity (changes within nested objects are not tracked).
  • The number of dependencies should not exceed 1000. (This is a performance consideration - avoid excessive memory usage).

Notes

  • Consider using an array to store the dependencies.
  • Think about how to handle duplicate dependencies.
  • Focus on the core logic of tracking and notifying dependencies. Error handling and more advanced features are not required for this challenge.
  • The initial value can be passed to the constructor. If no initial value is provided, the initial value should be undefined.
Loading editor...
typescript