import { useQuery } from "@tanstack/react-query";
import { fetchTickerData } from "../api";
import useCoinList from "./useCoinList";
import { useMemo } from "react";
interface Ticker {
coinCode: string;
price: string;
changeRate: number;
tradeVolume: string;
}
export default function useCoinTicker() {
const { markets } = useCoinList();
// markets 전체 대신 coinCode 목록으로만 변경 확인. queryKey에 추가하여 markets가 바뀔 때 패칭
const coinCodesKey = useMemo(
() => markets.map(({ coinCode }) => coinCode).join(","),
[markets]
);
// useQuery를 사용하여 ticker 데이터를 패칭하고, 1분마다 자동으로 새로 받아오도록 설정
const {
data: tickerData,
isLoading,
error,
} = useQuery({
queryKey: ["tickerData", coinCodesKey],
queryFn: fetchTickerData, // fetch function
refetchInterval: 60000, // 1분마다 자동으로 새로 패치
enabled: markets.length > 0, // markets 데이터가 있을 때만 실행되도록 설정
});
// 데이터가 로드되면 tickerData를 markets 배열의 순서대로 정렬, tickerData가 변경될 때만 tickerList를 재계산
const tickerList = useMemo(() => {
return markets
.map(({ coinCode }) => {
if (!tickerData) return null;
const ticker = tickerData.data[coinCode];
return ticker
? {
coinCode,
price: ticker.closing_price,
changeRate: parseFloat(ticker.fluctate_rate_24H),
tradeVolume: (ticker.acc_trade_value_24H / 1_000_000).toFixed(2),
}
: null;
})
.filter((item): item is Ticker => item !== null);
}, [tickerData]);
if (isLoading) {
return { tickerList: [], isLoading };
}
if (error) {
console.error("Error fetching ticker data:", error);
return { tickerList: [], error };
}
return { tickerList, isLoading, error };
}
문제: 1분이 채 지나지 않았는데, sidebar가 on/off 될때나, 정렬이 바뀔때마다 새로 api가 받아와 지고 있다.
처음에는 sortList 값에 따라 세 가지의 정렬 상태를 각각 캐싱한 후 sortList값 변경 시(좋아요 <->기본<->rsi순)에 캐싱된 값을 계속 보여 줄 생각이었다.
조건: 1분이 지나지 않으면 무슨 일이 있더라도 api를 받아와서는 안됌.
조건2: 마켓 순서가 바뀔 경우 이에 따라 ticker또한 순서가 바뀌면 됨. 또한 해당 순서는 3가지로 고정되어 있음. 매 변경시마다 굳이 비교하는게 아니라 특정 정렬 형태를 기억해 둔 후 그 형태로 변환하는게 나을 듯.
조건3: 마캣 정렬 순서에 따라 고정된 " ticker 데이터의 순서 3가지"를 기억해 뒀다가 마켓 순서가 변경시 이에 해당하는 순서를 찾아와 이에 맞춰 리스트를 정렬해야 함.
배열 자체를 저장하는 건 몰라도, 순서를 저장하는건 나로선 불가능했기에,
캐싱이 유지되는 한, coinCode 순서대로 (즉, sortList별) 정렬된 데이터를 각각 저장하고,
const ticker = tickerDataByCode[coinCode];
api 호출 기간이 채워지기 전 (그냥 호출 안하고 정렬만 바꿀때) 저장된 데이터를 화면에 띄우는 식으로 바꿨다.
또한 loading과 error를 없엤는데, ui에서 이미 tickerdata가 없을 경우 값들을 지정해뒀기 때문이다. .
staleTime: 5000, // 5초 동안 캐시된 데이터 사용
gcTime: 300000, // 5분동안 캐시 유지
gcTime은 설정한 시간 내에 화면 리렌더링이 있을 경우 캐시된 데이터를 보여준다.
statleTime은 화면을 띄워뒀을 때의 캐시 저장 기간이다. 해당 시간 내에 패칭이 발생할 경우 이를 막는다. 물론
이 시간이 지난다고 해서 새로 패칭이 받아와지는 건 아니고..
refetchInterval만큼 경과해야 패칭이 발생한다.
이상하게 5분 이내 화면을 켰다 꺼도 계속 console.log("ticker 재정렬"); 가 찍힌다.
ref로 기존 데이터를 저장해서 비교하거나 useQuery의 select문을 사용해서 데이터를 저장해봐도 해결할 수 없었다..
일단은 최적화 한 코드이다.
import { useQuery } from "@tanstack/react-query";
import { fetchTickerData } from "../api";
import useCoinList from "./useCoinList";
import { useMemo } from "react";
interface Ticker {
coinCode: string;
price: string;
changeRate: number;
tradeVolume: string;
}
export default function useCoinTicker() {
const { markets } = useCoinList();
// useQuery를 사용하여 ticker 데이터를 패칭하고, 6초초마다 자동으로 새로 받아오도록 설정
const { data: tickerData } = useQuery({
queryKey: ["tickerData"],
queryFn: fetchTickerData,
refetchInterval: 6000,
staleTime: 5000, // 5초 동안 캐시된 데이터 사용
gcTime: 300000, // 5분동안 캐시 유지
enabled: markets.length > 0,
});
// 데이터가 로드되면 tickerData를 markets 배열의 순서대로 정렬, tickerData가 변경될 때만 tickerList를 재계산
const tickerList = useMemo(() => {
if (!tickerData) {
console.log("ticker 데이터 없음");
return [];
}
const tickerDataByCode = tickerData.data;
console.log("ticker 재정렬");
return markets
.map(({ coinCode }) => {
const ticker = tickerDataByCode[coinCode];
return ticker
? {
coinCode,
price: ticker.closing_price,
changeRate: parseFloat(ticker.fluctate_rate_24H),
tradeVolume: (ticker.acc_trade_value_24H / 1_000_000).toFixed(2),
}
: null;
})
.filter((item): item is Ticker => item !== null);
}, [tickerData]);
return { tickerList };
}