Now.js Framework Documentation

Now.js Framework Documentation

WatchManager

EN 15 Dec 2025 08:18

WatchManager

Overview

WatchManager is the state change watching system in Now.js Framework. Used for tracking property changes and executing callbacks.

When to use:

  • Need to watch state changes
  • Need to react to property changes
  • Need deep object watching
  • Need debounced watchers

Why use it:

  • ✅ Deep and shallow watching
  • ✅ Debounce support
  • ✅ Immediate execution option
  • ✅ Dot notation paths
  • ✅ Array watching
  • ✅ Automatic cleanup

Basic Usage

Setup Watchers

const instance = {
  id: 'my-component',
  state: {
    count: 0,
    user: { name: 'John' },
    items: []
  }
};

WatchManager.setupWatchers(instance, instance.state, {
  // Simple watcher
  count(newVal, oldVal) {
    console.log(`Count changed: ${oldVal} → ${newVal}`);
  },

  // Deep watcher for objects
  user: {
    handler(newVal, oldVal) {
      console.log('User changed:', newVal);
    },
    deep: true
  },

  // Nested path
  'user.name'(newVal) {
    console.log('Name changed to:', newVal);
  }
});

Trigger Watchers

// After state change
instance.state.count++;
WatchManager.triggerWatchers(instance);

Watcher Options

WatchManager.setupWatchers(instance, state, {
  propertyName: {
    // Handler function
    handler(newVal, oldVal) {
      console.log('Changed:', newVal);
    },

    // Execute immediately
    immediate: false,

    // Deep watch (for objects/arrays)
    deep: false,

    // Debounce (ms)
    debounce: 0
  }
});

API Reference

WatchManager.setupWatchers(instance, state, watchers)

Setup watchers

Parameter Type Description
instance object Component instance
state object State object to watch
watchers object Watcher definitions
WatchManager.setupWatchers(component, component.state, {
  items: {
    handler(newItems) {
      this.render();  // 'this' = instance
    },
    deep: true
  }
});

WatchManager.triggerWatchers(instance)

Check and trigger watchers

Parameter Type Description
instance object Component instance
// Call after state mutations
instance.state.count++;
WatchManager.triggerWatchers(instance);

WatchManager.cleanupWatchers(instance)

Clear all watchers

Parameter Type Description
instance object Component instance
// On component destroy
WatchManager.cleanupWatchers(instance);

WatchManager.getDeepValue(path, obj)

Get value from dot notation path

Parameter Type Description
path string Dot notation path
obj object Source object

Returns: Any value

const name = WatchManager.getDeepValue('user.profile.name', state);

Watcher Patterns

Simple Property

{
  count(newVal, oldVal) {
    console.log('Count:', newVal);
  }
}

Deep Object

{
  user: {
    handler(newUser) {
      console.log('User changed:', newUser);
    },
    deep: true  // Watch nested changes
  }
}

Nested Path

{
  'settings.theme'(newTheme) {
    document.body.className = newTheme;
  }
}

Array Index

{
  'items[0]'(firstItem) {
    console.log('First item:', firstItem);
  }
}

Debounced

{
  searchQuery: {
    handler(query) {
      this.search(query);
    },
    debounce: 300  // Wait 300ms
  }
}

Immediate

{
  locale: {
    handler(locale) {
      this.loadTranslations(locale);
    },
    immediate: true  // Run on setup
  }
}

Real-World Examples

Form Validation

WatchManager.setupWatchers(form, form.state, {
  'data.email'(email) {
    const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    this.setFieldError('email', isValid ? null : 'Invalid email');
  },

  'data.password'(password) {
    const strength = calculateStrength(password);
    this.updatePasswordMeter(strength);
  }
});

Auto-Save

WatchManager.setupWatchers(editor, editor.state, {
  content: {
    handler(content) {
      this.saveToServer(content);
    },
    debounce: 1000,  // Save after 1s of no changes
    deep: true
  }
});

Computed Properties

WatchManager.setupWatchers(cart, cart.state, {
  items: {
    handler(items) {
      // Update computed total
      this.state.total = items.reduce((sum, item) => {
        return sum + (item.price * item.quantity);
      }, 0);
    },
    deep: true,
    immediate: true
  }
});

Common Pitfalls

⚠️ 1. Must Trigger After Mutation

// ❌ Watcher won't fire
state.count++;

// ✅ Trigger after mutation
state.count++;
WatchManager.triggerWatchers(instance);

⚠️ 2. Deep Watch for Objects

// ❌ Nested change not detected
{
  user(newUser) { ... }
}

// ✅ Use deep: true
{
  user: {
    handler(newUser) { ... },
    deep: true
  }
}

⚠️ 3. Cleanup on Destroy

// No cleanup = memory leak
function destroyComponent() {
  WatchManager.cleanupWatchers(instance);
}