대시보드 페이지는 정상적으로 출력되는데, 동일한 컴포넌트를 사용하는 모달에서 문제가 생기는 문제가 있었습니다.
최초 렌더링 후 모달을 띄울 경우는 정상적으로 내용이 출력되는데, 모달을 껐다 키면 내용이 출력되지 않습니다.
useEffect로 감싸고 있는 코드를 바깥으로 빼보기도 하고, 부모 컴포넌트를 만들어서 자식에게 props로 내려주는 방법도 해봤습니다.
import { useContext, useEffect, useState } from 'react';
import { SocketContext } from '@/components/Common/Socket/SocketContext';
import { isNil } from '@/utils/type';
import type { Dashboard, Rank } from './types';
const INTERVAL_TIME = 5000;
export function useParticipantDashboard() {
const { socket } = useContext(SocketContext);
const [ranks, setRanks] = useState<Rank[]>([]);
const [myRank, setMyRank] = useState<Rank>({
email: '',
score: 0,
problemDict: {},
});
const [totalProblemCount, setTotalProblemCount] = useState(-1);
function handleDashboard(newDashboard: Dashboard) {
setRanks(newDashboard.rankings);
setMyRank(newDashboard.myRanking);
setTotalProblemCount(newDashboard.totalProblemCount);
}
useEffect(() => {
if (isNil(socket)) return;
if (!socket.hasListeners('dashboard')) {
socket.on('dashboard', handleDashboard);
}
}, [socket]);
if (!isNil(socket)) socket.emit('dashboard');
useEffect(() => {
const intervalId = setInterval(() => {
if (!isNil(socket)) socket.emit('dashboard');
}, INTERVAL_TIME);
return () => clearInterval(intervalId);
}, []);
return {
ranks,
myRank,
totalProblemCount,
};
}
여기에서
import { useContext, useEffect, useState } from 'react';
import { SocketContext } from '@/components/Common/Socket/SocketContext';
import { isNil } from '@/utils/type';
import type { Dashboard, Rank } from './types';
const INTERVAL_TIME = 5000;
export function useParticipantDashboard() {
const { socket } = useContext(SocketContext);
const [ranks, setRanks] = useState<Rank[]>([]);
const [myRank, setMyRank] = useState<Rank>({
email: '',
score: 0,
problemDict: {},
});
const [totalProblemCount, setTotalProblemCount] = useState(-1);
function handleDashboard(newDashboard: Dashboard) {
setRanks(newDashboard.rankings);
setMyRank(newDashboard.myRanking);
setTotalProblemCount(newDashboard.totalProblemCount);
}
useEffect(() => {
if (!isNil(socket)) socket.emit('dashboard');
const intervalId = setInterval(() => {
if (!isNil(socket)) socket.emit('dashboard');
}, INTERVAL_TIME);
return () => clearInterval(intervalId);
}, [socket]);
useEffect(() => {
if (isNil(socket)) return;
if (!socket.hasListeners('dashboard')) {
socket.on('dashboard', handleDashboard);
}
return () => { // 이 부분!!!!
if (socket.hasListeners('dashboard')) {
socket.off('dashboard', handleDashboard);
}
};
}, [socket]);
return {
ranks,
myRank,
totalProblemCount,
};
}
useEffect 안에 정리 함수를 사용했더니 해결되었습니다!
원래 코드에서는 소켓 리스너를 추가할 때에는 컴포넌트가 마운트될 때만 확인하고, 제거할 때는 컴포넌트가 언마운트될 때만 확인하고 있었습니다. 그러나 수정된 코드에서는 소켓 리스너를 추가하는 부분과 제거하는 부분이 모두 useEffect
안에 들어가 있기 때문에, 컴포넌트가 마운트되거나 언마운트될 때 모두 실행되게 됩니다.
문제 해결을 위해 수정된 코드에서는 두 번째 useEffect
내부에서 컴포넌트가 마운트될 때만 리스너를 추가하고, 컴포넌트가 언마운트될 때에만 리스너를 제거하도록 하였습니다. 이렇게 하면 리스너가 중복으로 추가되지 않고, 컴포넌트가 마운트되었을 때에만 리스너가 활성화되어 정상적으로 동작하게 됩니다.