<aside> <img src="/icons/bookmark_purple.svg" alt="/icons/bookmark_purple.svg" width="40px" />
목차
</aside>
현재 room이라는 하나의 큰 컴포넌트내에서 questionView와 resultView로 뷰가 나뉘어져있다.
questionView: 질문 응답 뷰
resultView : 통계결과를 표시하는 뷰
questionView(질문응답 뷰) → resultView(통계결과 뷰)로 넘어올 때,
questionview에서 마지막 질문이 끝나면 뷰를 전환을 시키고, resultview가 렌더링 되면서, 소켓 이벤트를 등록했다.
하지만 소켓 이벤트를 등록했음에도 결과뷰 렌더링시 서버로부터 응답이 오지 않았는데,
그 이유는 뷰가 전환되는 사이에 통계 알림이 오고, 그 이후에 이벤트 리스너가 늦게 등록되었기 때문이다.
마지막 질문이 끝나면서 타이머가 종료되고, 페이지 전환하고(startResultLoading), 로딩을 시작(startResultLoading)했을때는, 이미 통계결과가 와있어서 그 이벤트 헨들러인 finishloading이 먼저 진행되고있었다.
예상 순서 : startReesultPage → startResultLoading → finishResultLoading
테스트 결과: finishResultLoading → startReesultPage → startResultLoading
if (socket && socket.connected) { const handleResult = (response: CommonResult) => { if (Object.keys(response).length > 0) { finishResultLoading(); ... } else { openToast({ type: 'error', text: '통계 분석 중 오류가 발생했습니다. 다시 시도해주세요' }); } }; socket.on('empathy:result', handleResult); }
기존 resultview에서 소켓 리스너를 등록하는것이 아닌 뷰 전환이 되기 전, questionview 에서 미리 이벤트리스너를 등록해주면된다.
즉, 타이머가 종료될 때까지 전역 상태로 관리되는 통계처리를 지연시키고, 소켓 응답의 response를 임시 데이터로 저장한다.
const handleResult = (response: CommonResult) => {
// 통계결과를 임시로 저장
resultResponseRef.current = response;
};
...
socket.on('empathy:result', handleResult);
마지막 질문이 끝났을 때 로딩을 띄우고, 그때서야 임시로 저장돼있던 통계데이터를 처리한다.
useEffect(() => {
if (currentQuestionIndex >= questions.length) {
timerWorker.current?.postMessage({ action: 'stop' }); // 타이머 중지
if (questions.length > 0) {
//마지막 질문이 끝나고 로딩 시작
onLastQuestionComplete();
startResultLoading();
setTimeout(() => {
if (resultResponseRef.current) {
// 통계 데이터 처리
setStatisticsKeywords(resultResponseRef.current);
Object.entries(resultResponseRef.current).forEach(([userId, array]) => {
setParticipants((prev) => ({ ...prev, [userId]: { ...prev[userId], keywords: array } }));
});
} else {
openToast({ type: 'error', text: '통계 분석 중 오류가 발생했습니다. 다시 시도해주세요' });
}
finishResultLoading();
setOutOfBounds(false); //사용자 ui 원위치로
socket?.off('empathy:result', handleResult);
}, 3000);
}
return;
}
이렇게 하면, 뷰 전환 이전에 소켓 응답이 오더라도 놓치지 않고 결과를 처리할 수 있게 된다.
뷰 전환이나 타이밍 제어가 어려운 경우, 일부러 로딩 시간을 주입하여 서버로부터의 응답을 기다린 후에 결과를 처리하는 것이 더 자연스러울 수 있다.
여기서는 의도적으로 3초 동안 로딩을 표시한 뒤에 통계 결과를 보여주거나 오류 메시지를 띄우는 방식으로 처리했다.
로딩을 통한 지연을 일부러 주입시킨 이유는 다음과 같다.