본문 바로가기

[Datepicker] useState의 비동기적 특성으로 상태 업데이트 지연 이슈

@Jeeqong 2024. 10. 11. 11:41
반응형
🚨 React DatePicker의 Range 선택 문제 해결하기
React 프로젝트에서 DatePicker를 사용할 때, range 선택 시 첫 번째 날짜 선택 후 즉시 반영되지 않는 문제가 발생했다.
이는 React의 useState 비동기 업데이트 특성 때문인데
이 글에서는 이 문제를 해결하는 최적의 방법을 소개합니다.

1. 문제 상황

🔹 개발 조건

  • DatePickerType="range" 또는 "single" (기본값은 "single")
  • 달력은 하나만 사용하여 시작일과 종료일을 선택
  • 첫 번째 선택한 날짜는 시작/종료일 구분 없음
  • 두 번째 클릭한 날짜와 비교하여 범위를 자동 설정
    • 두 번째 날짜가 더 작으면 → 첫 번째 날짜를 endDate, 두 번째 날짜를 startDate로 설정
    • 두 번째 날짜가 더 크면 → 첫 번째 날짜를 startDate, 두 번째 날짜를 endDate로 설정
    • isRangeSelected = true가 되면 창 닫기
  • 기간 선택이 완료된 상태에서 새로 클릭하면 기존 설정 초기화 후 새 날짜 선택

2. 코드 예제 (문제 발생 코드)

const [startDate, setStartDate] = useState<Date | null>(null);
const [endDate, setEndDate] = useState<Date | null>(null);

if (!startDate || isRangeSelected) {
	setStartDate(selectedDate);  // 첫 번째 날짜 선택
} else {
    // 두 번째 날짜와 첫 번째 날짜 비교
    if (selected < startDate) {
        setStartDate(selected);  // 두 번째 날짜가 더 작으면 첫 번째 날짜로 설정
        setEndDate(startDate);   // 첫 번째 날짜를 종료일로 설정
    } else {
        setEndDate(selected);    // 두 번째 날짜가 더 크면 종료일로 설정
    }
}


3. 원인 분석 🔍

❌ 상태가 즉시 반영되지 않는 이유

useState는 비동기적으로 동작합니다.

즉, setState 호출 직후 상태가 바로 변경되지 않고, 다음 렌더링에서 반영됩니다.

💡 문제 발생 흐름

  1. 사용자가 날짜 A를 선택 → startDate가 A로 설정됨 (하지만 즉시 반영되지 않음)
  2. 사용자가 날짜 B를 선택 → startDate가 아직 이전 값을 가지고 있어서 비교가 올바르게 되지 않음
  3. setState가 비동기적으로 동작하여 UI 업데이트가 늦어짐 → 첫 번째 선택한 날짜가 화면에 즉시 표시되지 않음

4. 해결 방법 🚀

💡 변수로 날짜를 저장하고, 한 번에 useState 업데이트하기

  • 날짜를 useState에 즉시 반영하는 대신, 로컬 변수를 사용하여 계산 후 한 번에 setState
  • 첫 번째 선택한 날짜를 화면에 즉시 표시해야 하므로, selectDate라는 별도 상태를 활용

✅ 수정된 코드

const [selectDate, setSelectDate] = useState<Date | null>(null);
const [startDate, setStartDate] = useState<Date | null>(null);
const [endDate, setEndDate] = useState<Date | null>(null);

if (!selectDate || isRangeSelected) {
    // 첫 번째 날짜 선택 (기존 설정 초기화)
    resetRangeSelection();
    setSelectDate(selected);
} else {
    let start, end;
    // 두 번째 날짜 선택 (범위 선택)
    if (selected < selectDate) {
        start = selected;
        end = selectDate;
    } else {
        start = selectDate;
        end = selected;
    }

    // 한 번에 상태 업데이트
    setStartDate(start);
    setEndDate(end);

    // 선택 완료 후 이벤트 처리
    if (onClose) onClose();
    if (onChange) {
        onChange({
            start: dateToString(start),
            end: dateToString(end),
        });
    }
}

5. 핵심 포인트 ✅

첫 번째 선택한 날짜를 UI에 즉시 반영

  • selectDate를 별도 상태로 관리하여 즉시 화면에 반영

비동기적 setState 문제 해결

  • startDate와 endDate를 한 번에 업데이트
  • useState를 연속적으로 호출하는 대신, 변수(start, end)를 사용해 논리적으로 처리

새로운 날짜 선택 시 기존 범위 초기화

  • isRangeSelected가 true가 되면 resetRangeSelection()을 호출하여 이전 설정을 초기화
  • 새 날짜 선택 시 기존 startDate, endDate를 삭제하고 새 값으로 설정

6. 결론 

React의 useState 비동기 특성을 이해하는 것이 중요

변수(start, end)를 활용하여 한 번에 setState 적용

첫 번째 선택한 날짜가 즉시 화면에 반영되도록 selectDate 추가

 



반응형
Jeeqong
@Jeeqong :: JQVAULT

Jeeqong's vault : 정보/기록을 쌓아두는 공간 웹개발 포스팅 일상 리뷰를 기록하는 공간입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차