React.js
Ref와 Polling 방식을 사용하여 게임 데이터 준비 이후 실행 처리
Chunho
2024. 10. 8. 20:05
서버에서 응답으로 내려주는 데이터 중 게임 실행 준비가 완료되었다는 상태가 있을 경우, 폴링을 사용하여 로딩 Indicator를 돌리다가 실행 처리를 해줄 수 있다.
위 기능을 간단하게 구현해보기 위해 hook을 하나 만들어주었다.
const wrapPollingRef = useRef(false);
우선 Ref 하나를 생성해 준다.
const { mutate: play, isLoading } = usePostAPIExEndPoint({
mutation: {
onSuccess: (data) => {
if (data.result === "SUCCESS") {
showLoading();
setGameStatus({
...gameStatus,
playId: data.playId,
});
wrapPollingRef.current = true;
} else {
openErrorModal();
}
},
onError: () => {},
},
});
이후 Play버튼 클릭 시의 이벤트를 제어해주는 mutation을 만든 뒤 play함수는 hook을 연결하는 컴포넌트에서 받아 이벤트에 연결한다.
const { data: resultData } = useGetExample(gameStatus.id, {
query: {
enabled: wrapPollingRef.current && gameStatus.id !== -1,
refetchInterval: 1000,
onSuccess: (data) => {
if (data.completed && wrapPollingRef.current) {
hideLoading();
setGameStatus({
...gameStatus,
playStatus: "IN_PROGRESS",
});
wrapPollingRef.current = false;
(async () => {
setPageTransition(true);
await WaitForSeconds(500);
setPageTransition(false);
playAction();
})();
}
},
},
});
이후 게임 실행이 준비될 때 까지 계속해서 요청을 하며, 준비가 된 경우 로딩 인디케이터를 숨기고 게임을 진행하는 간단한 기능을 만들 수 있었다.
추가적으로 버튼을 연속해서 빠르게 클릭하는 경우 서버로 여러개의 요청이 들어가는 것을 방지하는 예외처리를 하기 위해
export const throttling = (throttleTimePerMs = 500) => {
let timer: ReturnType<typeof setTimeout> | null = null;
const throttleFunc = (callbackFunc: () => void) => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
}, throttleTimePerMs);
try {
callbackFunc();
} catch (error) {
console.error("Error in throttled function:", error);
if (timer) {
clearTimeout(timer);
timer = null;
}
}
}
};
return throttleFunc;
};
위와 같이 간단한 쓰로틀링 기능을 추가로 만들어줬다.
연속 이벤트 자체를 방지하는것이 아닌, 순간적으로 많은 요청이 들어가는것만 방지하기 위해서라면 useMutation이 제공하는 isLoading을 사용하는 것도 좋을 것 같다.