All files / src/utils/createEvent createEvent.ts

100% Statements 13/13
50% Branches 1/2
100% Functions 3/3
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 839x   9x 9x                                                                                                                         9x 5x 5x 5x   5x 5x   5x     5x 5x     5x      
import { unwatch } from '../unwatch'
 
import { forceQueueWatchers } from '../../Compute'
import { scope } from '../../constants'
 
/**
 * **Creates reactive event function** (unlike `event` which executes immediately).
 *
 * Like `event`, `createEvent`:
 * - **Ignores** automatic state subscriptions (`unwatch`)
 * - **Batches** state updates and **flushes queue** at the end
 * - Perfect for **event handlers** and **mutations**
 * - **Returns function** for later execution (unlike `event`)
 *
 * @example Basic usage
 * ```ts
 * const count = new State(0)
 *
 * const increase = createEvent(() => {
 *   console.log(count.value++)
 * })
 *
 * new Watch(() => console.log(count.value))
 * // logs: 0
 *
 * increase() // logs: 1 (executes now)
 * ```
 *
 * @example Batch multiple updates (single watcher notification)
 * ```ts
 * const a = new State(0)
 * const b = new State(0)
 *
 * const increase = createEvent(() => {
 *   a.value++
 *   b.value++
 * })
 *
 * new Watch(() => console.log(a.value, b.value))
 * // logs: 0, 0
 *
 * reset() // logs: 0, 0 (BOTH updated, ONE notification!)
 * ```
 *
 * @example Returns value from callback
 * ```ts
 * const count = new State(0)
 *
 * const increase = createEvent(() => count.value++)
 *
 * new Watch(() => console.log(count.value))
 * // logs: 0
 *
 * const prev = increase()
 * // logs: 1
 *
 * console.log(prev)
 * // logs: 0
 * ```
 *
 * @param callback - Effect callback to wrap in event
 * @returns Reusable event function with same signature as `callback`
 * @template F - callback function type
 */
export function createEvent<F extends (...args: any[]) => any> (callback: F): F {
  return function (...args: any[]) {
    const result = unwatch(() => {
      scope.eventDeep++
      // @ts-expect-error this
      const result = callback.apply(this, args)
      scope.eventDeep--
 
      return result
    })
 
    Eif (!scope.eventDeep) {
      forceQueueWatchers()
    }
 
    return result
  } as unknown as F
}