Files
auto-trade/features/dashboard/hooks/use-price-flash.ts

74 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-02-13 12:17:35 +09:00
"use client";
import { useEffect, useRef, useState } from "react";
const FLASH_DURATION_MS = 2_000;
/**
* @description (+/-) .
* @param currentPrice
* @param key ( )
* @returns (up/down, ) null
* @remarks UI 흐름: 시세 -> usePriceFlash -> -> 2
* @see features/dashboard/components/HoldingsList.tsx
* @see features/dashboard/components/StockDetailPreview.tsx
*/
export function usePriceFlash(currentPrice: number, key?: string) {
const [flash, setFlash] = useState<{
val: number;
type: "up" | "down";
id: number;
} | null>(null);
const prevKeyRef = useRef<string | undefined>(key);
const prevPriceRef = useRef<number>(currentPrice);
const timerRef = useRef<number | null>(null);
useEffect(() => {
const keyChanged = prevKeyRef.current !== key;
if (keyChanged) {
prevKeyRef.current = key;
prevPriceRef.current = currentPrice;
if (timerRef.current !== null) {
window.clearTimeout(timerRef.current);
timerRef.current = null;
}
const resetTimerId = window.setTimeout(() => {
setFlash(null);
}, 0);
return () => window.clearTimeout(resetTimerId);
}
const prevPrice = prevPriceRef.current;
const diff = currentPrice - prevPrice;
prevPriceRef.current = currentPrice;
if (prevPrice === 0 || Math.abs(diff) === 0) return;
// 플래시가 보이는 동안에는 새 플래시를 덮어쓰지 않아 화면 잔상이 지속되지 않게 합니다.
if (timerRef.current !== null) return;
setFlash({
val: diff,
type: diff > 0 ? "up" : "down",
id: Date.now(),
});
timerRef.current = window.setTimeout(() => {
setFlash(null);
timerRef.current = null;
}, FLASH_DURATION_MS);
}, [currentPrice, key]);
useEffect(() => {
return () => {
if (timerRef.current !== null) {
window.clearTimeout(timerRef.current);
}
};
}, []);
return flash;
}