🔔 Side Effects & Callbacks

Register callbacks and work with observables directly

Interactive Side Effects Demo

Current State & Document Title

Name: Alice

Age: 25

Email: alice@example.com

Document Title:

(Check your browser tab!)

Name Changes

Age Changes

Email Changes

Side Effects Log

No side effects triggered yet. Try changing some values above!

Active Side Effects Code:

// Register callbacks
const cleanup = userStore.register("age", (newAge) => {
  if (newAge >= 18) {
    console.log("🎉 User is now an adult!");
  }
});

// Observable
userStore.observable("name").subscribe((name) => {
  document.title = `Welcome, ${name}!`;
});

// Don't forget to cleanup when component unmounts
cleanup();

🔄 Side Effects Use Cases

Side effects are perfect for:

  • Analytics: Track user actions and state changes
  • Notifications: Show toasts when certain conditions are met
  • API Calls: Sync data to server when state changes
  • Local Storage: Persist state changes automatically
  • DOM Updates: Update document title, favicon, etc.
  • Third-party Integrations: Trigger external services

Register Callbacks

// Register callback for age changes
userStore.register("age", (newAge) => {
  if (newAge >= 18) {
    console.log("User is now an adult!");
    // Trigger analytics, notifications, etc.
  }
});

// Multiple callbacks for the same field
userStore.register("name", (name) => {
  console.log(`Name changed to: ${name}`);
});

userStore.register("name", (name) => {
  document.title = `Welcome, ${name}!`;
});

Observables

// Direct observable access
userStore.observable("name").subscribe((name) => {
  document.title = `Welcome, ${name}!`;
});

// Advanced observable operations
userStore.observable("age")
  .pipe(
    filter(age => age >= 18),
    debounceTime(1000),
    distinctUntilChanged()
  )
  .subscribe(age => {
    console.log(`Adult age confirmed: ${age}`);
  });

Complex Side Effects Example

import { combineLatest } from "next-tiny-rx-store";
import { debounceTime, distinctUntilChanged } from "next-tiny-rx-store";

// Combine multiple observables for complex side effects
combineLatest([
  userStore.observable("name"),
  userStore.observable("age"),
  userStore.observable("email")
]).pipe(
  debounceTime(500), // Wait for 500ms of inactivity
  distinctUntilChanged((prev, curr) => 
    JSON.stringify(prev) === JSON.stringify(curr)
  )
).subscribe(([name, age, email]) => {
  // Save to localStorage
  localStorage.setItem("userProfile", JSON.stringify({
    name, age, email, lastUpdated: Date.now()
  }));
  
  // Send analytics event
  analytics.track("User Profile Updated", { name, age, email });
  
  // Show success notification
  showNotification("Profile saved successfully!");
});

💡 Best Practices

Performance:

  • Use debounceTime for expensive operations
  • Use distinctUntilChanged to prevent duplicate calls
  • Unsubscribe from observables when components unmount

Error Handling:

  • Wrap side effects in try-catch blocks
  • Use built-in error handling
  • Log errors appropriately for debugging