반응형
D-day 기능 구현과 옵저버
유저 피드백을 받으면서 D-day가 생겼다.
마감일을 기준으로 프로젝트 모집이 며칠이나 남았는지 보였으면 좋겠다는 피드백이었다.
처음 짠 코드는 이랬다.
//디데이 계산
export const getDays = (milliseconds: number) => {
const date = new Date(milliseconds);
const day = `${date.getDate() - 1}`.padStart(2);
return `${day}`;
};
생략
const day = Number(getDays(deadline - today));
return(
<ImageWrap>
<ContentCardImgContainer
src={thumbnail || defaultThumbnail}
onClick={onNavigateToProjectDetailEvent(id)}
alt={title + ` 프로젝트 썸네일`}
/>
{isRecruiting && day >= 0 && ( // 현재 모집 중이고 남은 일자가 0일 이상이면
<DeadLineIcon day={day}>
{day === 0 ? '마감일' : `D - ${getDays(deadline - today)}`}
</DeadLineIcon>
)}
</ImageWrap>
...
중략
const DeadLineIcon = styled.div<{ day: number }>`
z-index: 1000;
position: absolute;
top: 10px;
right: 10px;
width: 3.75rem;
height: 1.75rem;
font-style: normal;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
border-radius: 2.5rem;
/* padding: 0rem 0.5rem; */
background-color: ${({ day }) =>
day <= 3 ? `${COLORS.red}` : `${COLORS.gray100}`};
color: ${({ day }) => (day <= 3 ? `${COLORS.white}` : `${COLORS.gray400}`)};
font-size: 0.75rem;
`;
하지만 이 부분에서 남은 일수를 계산하는 부분이 모호했다.
계산이 아니라 일자를 끼워맞췄다.
날짜 함수 때문인지 staleTime 때문인지 12시 땡하고 디데이가 업데이가 되지 않았다.
나는 12시 땡하면 D-day가 바뀌길 원했다.
그래서 디데이 계산 함수를 수정했다.
//디데이 계산
export const getDays = (milliseconds: number) => {
const hours = Math.floor(milliseconds / (1000 * 60 * 60));
return Number(Math.floor(hours / 24));
};
처음에 짰던 코드는 날짜로 변환해서 일자로 가져오는건 로직이었기 때문에 잘못됐고 deadline에서 지금 시간을 뺀 수를 24로 나눠 일자로 계산했다.
const [RemainDays, setRemainDays] = useState(getDays(deadline - today));
let today: any = Date.now();
useEffect(() => {
const intervalId = setInterval(() => {
const timeDiff = deadline - today;
setRemainDays(getDays(timeDiff));
if (timeDiff <= 0) {
updateRecruitingMutate(id, false as any);
}
console.log(getDays(timeDiff), getDateAndTime(today));
}, 1000 * 60 * 10); //10분에 한번씩 모니터링
return () => clearInterval(intervalId);
}, []);
그리고 setInterval을 사용하여 옵저버를 만들었다.
10분에 한번씩 모니터링 하여 업데이트할 수 있도록 한다.
테스트를 위해 현재 시간을 23시 59분으로 설정한 후 2초에 한번씩 1분이 지나게 했다.
이렇게 하면 12시가 되자마자 D-day가 업데이트 되는 것을 확인 할 수 있다.
하지만 리액트에서 이렇게 setInterval을 사용해 옵저버를 만들었을 때 다음과 같은 문제점이 발생한다.
- 메모리 누수(Memory leaks) : setInterval은 컴포넌트가 언마운트(unmount)되어도 계속 실행될 수 있다. 이는 메모리 누수로 이어지며 컴포넌트가 언마운트될 때 반드시 clearInterval을 호출하여 이를 방지해야 한다.
- 성능 저하 : setInterval은 일정한 시간 간격으로 작업을 수행하므로 불필요한 렌더링이 발생할 수 있다. 예를 들어, setInterval이 1초마다 실행되는 경우, 1초마다 상태(state)가 변경될 때마다 컴포넌트가 다시 렌더링되어 성능이 저하될 수 있다.
- 상태 업데이트 문제 : setInterval로 상태를 업데이트하는 경우, 이전 상태를 기반으로 새로운 상태를 계산해야 한다. 하지만 React에서 상태 업데이트는 비동기(asynchronous)로 처리되므로, 이전 상태가 바로 반영되지 않을 수 있다. 이로 인해 예상치 못한 결과가 발생할 수 있다.
그렇기 때문에 정말 꼭 필요한 곳이 아니라면 사용하지 않아도 좋을 것 같다.
우리 프로젝트에서는 invalidateQueries를 사용하기 때문에 옵저버는 필요하지 않을 것 같아서 날짜 변환 함수만 적용했다.
반응형
'매일 해내는 개발 > Develog' 카테고리의 다른 글
[Develog] npm의 --save, --save-dev 등의 플래그와 그 종류 (0) | 2023.03.12 |
---|---|
기술 면접 대비 질문과 답 #1 (0) | 2023.03.10 |
[Develog] yarn berry (0) | 2023.03.06 |
[Develog] 좋아요 기능 구현2 (0) | 2023.03.01 |
[Develog] 좋아요 기능 구현(with firebase, useQuery, useMutation) (0) | 2023.02.25 |
댓글