import { useCallback, useEffect, useRef, useState } from 'react'; export function useRafBatched<T extends (...args: any[]) => void>(callback: T): T { // TODO: // 1) useRef 로 pending rafId (또는 null), latestArgs, latestCallback 저장 // 2) callback이 바뀔 때마다 ref 갱신 (stale closure 방지) // 3) 반환 함수: latestArgs 갱신 → 이미 pending이면 return → 아니면 rAF schedule // 4) rAF tick: latestCallback(...latestArgs!) 호출 후 rafId/args 초기화 // 5) useEffect cleanup: rafId 있으면 cancelAnimationFrame return ((..._args: any[]) => { throw new Error('Not implemented'); }) as T; } export function ScrollIndicator() { const [percent, setPercent] = useState(0); const update = useRafBatched((p: number) => setPercent(p)); return ( <div data-testid="scroller" style={{ height: 400, overflow: 'auto' }} onScroll={(e) => { const el = e.currentTarget; const p = Math.round((el.scrollTop / (el.scrollHeight - el.clientHeight)) * 100); update(p); }} > <div style={{ height: 2000 }}> <p data-testid="percent">{percent}%</p> <p>스크롤 해보세요. percent 업데이트는 한 프레임당 1번으로 묶입니다.</p> </div> </div> ); }
Tests