Effects & Reactivity

Perform side effects (API calls, timers, DOM manipulation) automatically when your state changes.

Reacting to Changes

Pass a function and a dependency array to pp.effect. The function runs whenever a variable in the array changes.

live-search.html
<div class="space-y-2">
  <input 
    type="text" 
    value="{query}" 
    placeholder="Search users..." 
    oninput="setQuery(event.target.value)"
    class="border p-2 rounded w-full"
  />
  
  <p class="text-sm text-gray-500">
    {isLoading ? 'Searching...' : results.length + ' results found.'}
  </p>
</div>

<script type="text/pp">
  const [query, setQuery] = pp.state("");
  const [results, setResults] = pp.state([]);
  const [isLoading, setLoading] = pp.state(false);

  // Run this effect whenever 'query' changes
  pp.effect(() => {
    if (!query) {
        setResults([]);
        return;
    }

    setLoading(true);

    // Simulate an API call
    setTimeout(() => {
       const mockDB = ["Alice", "Bob", "Charlie", "Dave"];
       const filtered = mockDB.filter(n => 
         n.toLowerCase().includes(query.toLowerCase())
       );
       
       setResults(filtered);
       setLoading(false);
    }, 500);

  }, [query]); // <-- Dependency Array
</script>

Cleanup & Lifecycle

If your effect creates a resource (like a Timer or Event Listener), return a cleanup function. PulsePoint runs this function before re-running the effect or when the component unmounts.

Memory Leaks: Always return a cleanup function for setInterval, addEventListener, or WebSocket connections.
stopwatch.html
<div>
  <p class="text-2xl font-mono">Time: {seconds}s</p>
  
  <div class="flex gap-2 mt-2">
    <button onclick="setRunning(true)" disabled="{isRunning}">Start</button>
    <button onclick="setRunning(false)" disabled="{!isRunning}">Stop</button>
  </div>
</div>

<script type="text/pp">
  const [seconds, setSeconds] = pp.state(0);
  const [isRunning, setRunning] = pp.state(false);

  pp.effect(() => {
    // Only set up the timer if we are running
    if (isRunning) {
      const timerId = setInterval(() => {
        setSeconds(s => s + 1); // Functional update usually safer
      }, 1000);

      // CLEANUP: Runs when isRunning changes to false, or component dies
      return => clearInterval(timerId);
    }
  }, [isRunning]);
</script>

Dependency Array Cheat Sheet

Control exactly when your effect runs by adjusting the second argument.

Syntax Behavior
pp.effect(fn, [prop]) Runs on mount, and whenever prop changes.
pp.effect(fn, []) Runs once on mount. (Great for initial API calls).
pp.effect(fn) Runs on every render. (Use with caution).
State Next: Ref