{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-interval",
  "title": "useInterval",
  "description": "A declarative setInterval hook with a nullable delay, an always-fresh callback, and pause/resume controls.",
  "files": [
    {
      "path": "src/registry/hooks/use-interval.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nexport interface UseIntervalOptions {\n  /** interval 每次被(重新)建立时先同步执行一次 callback:挂载、resume、delay 变化。默认 false。 */\n  immediate?: boolean\n}\n\nexport interface UseIntervalControls {\n  /** 停表:清掉当前 interval,`isPaused` 变 true。 */\n  pause: () => void\n  /** 继续:按当前 `delay` 重新建 interval(`immediate` 为 true 时先执行一次)。 */\n  resume: () => void\n  isPaused: boolean\n}\n\n/**\n * 声明式的 `setInterval`:`delay` 传 `null` 即暂停(不建计时器),另返回\n * `{ pause, resume, isPaused }` 给需要按钮控制的场景。\n *\n * 核心是**最新 callback 存 ref**:effect 每次渲染只更新 `savedCallback.current`,\n * 而建 interval 的 effect 依赖里根本没有 `callback` —— 于是消费者写内联箭头函数\n * (几乎总是如此,而且闭包里往往捕获着会变的 state)不会每次渲染都 clear + 重建\n * 计时器,节奏不会被重置,但每次 tick 调到的又永远是最新那份闭包。\n *\n * - `delay` 变化时重建 interval(新周期立即生效);`delay` 不变则计时器原样保留。\n * - `pause()` / `resume()` 走的是同一条重建路径:`isPaused` 是建 interval 那个\n *   effect 的依赖,置 true 时 cleanup 清掉计时器,置 false 时重新建。\n * - **SSR 安全**:计时器只在 effect 里建,渲染期不碰任何浏览器 API;卸载时\n *   `clearInterval` 必被调用,不会有 tick 打在已卸载的组件上。\n */\nexport function useInterval(\n  callback: () => void,\n  delay: number | null,\n  options: UseIntervalOptions = {},\n): UseIntervalControls {\n  const { immediate = false } = options\n  const [isPaused, setIsPaused] = React.useState(false)\n\n  const savedCallback = React.useRef(callback)\n  React.useEffect(() => {\n    savedCallback.current = callback\n  })\n\n  React.useEffect(() => {\n    if (delay === null || isPaused) return\n\n    if (immediate) savedCallback.current()\n\n    const id = setInterval(() => savedCallback.current(), delay)\n    return () => clearInterval(id)\n  }, [delay, isPaused, immediate])\n\n  const pause = React.useCallback(() => setIsPaused(true), [])\n  const resume = React.useCallback(() => setIsPaused(false), [])\n\n  return { pause, resume, isPaused }\n}\n\nexport default useInterval\n",
      "type": "registry:hook"
    }
  ],
  "type": "registry:hook"
}