TIL: React의 useEffect와 상태 관리 이해하기
- 오늘 timer 의 시간이 0초가 되었을 때, 새로고침을 해야 모달이 뜨는 현상이 발생했습니다. 해당 내용을 학습하고자 useEffect와 상태관리를 공부하여, 0초가 되었을 때 새로고침 없이 modal 이 뜨도록 설정했습니다.
1. useEffect란 무엇인가?
useEffect는 React 훅(Hook)의 하나로, 컴포넌트에서 "부수 효과(side effect)"를 수행할 수 있게 해줍니다. 부수 효과란 데이터 가져오기, 타이머 설정, 이벤트 구독 같은 외부와의 상호작용을 말합니다.
useEffect(() => {
// 실행할 코드
}, [의존성 배열]);
2. 의존성 배열의 역할
의존성 배열은 useEffect가 언제 실행될지 결정하는 중요한 요소입니다:
빈 배열
[]
: 컴포넌트가 처음 화면에 나타날 때(마운트될 때)만 한 번 실행됩니다.useEffect(() => { console.log("컴포넌트가 화면에 나타났습니다!"); }, []);
의존성 있는 배열
[값1, 값2]
: 컴포넌트가 마운트될 때와 배열 안의 값이 변경될 때마다 실행됩니다.useEffect(() => { console.log("count가 변경되었습니다:", count); }, [count]);
의존성 배열 생략: 컴포넌트가 마운트될 때와 업데이트될 때마다 실행됩니다(거의 모든 렌더링마다).
useEffect(() => { console.log("컴포넌트가 업데이트되었습니다!"); });
3. 상태(State) 관리와 useState
useState는 컴포넌트에서 변경 가능한 상태를 관리하는 훅입니다:
const [timeLeft, setTimeLeft] = useState(600); // 초기값 600초
timeLeft
: 현재 상태 값setTimeLeft
: 상태를 업데이트하는 함수
4. 함수형 업데이트와 prev
상태를 업데이트할 때 이전 상태 값을 기반으로 계산이 필요한 경우, 함수형 업데이트를 사용합니다:
// 일반 업데이트
setTimeLeft(timeLeft - 1);
// 함수형 업데이트 (더 안전한 방법)
setTimeLeft(prev => prev - 1);
여기서 prev
는 현재 상태의 최신 값을 나타내는 매개변수입니다. 함수형 업데이트는 이전 상태에 의존하는 업데이트를 여러 번 할 때 더 안정적입니다.
5. 타이머 구현 예제 분석
문제 상황
타이머가 특정 시간(590초)에 도달했을 때 모달을 표시하려고 하는데, 새로고침을 해야만 모달이 나타나는 문제가 있었습니다.
원인
첫 번째 useEffect에서 조건을 확인했지만, 이 useEffect는 컴포넌트 마운트 시에만 실행되기 때문에 타이머가 실시간으로 변할 때 조건을 확인하지 못했습니다.
// 문제가 있던 코드
useEffect(() => {
// 초기 설정 로직
const remaining = 60 * 10 - elapsedSeconds;
if (remaining <= 590) { // 이 조건은 마운트 시에만 확인됨!
setShowTimeoutModal(true);
} else {
setTimeLeft(remaining);
}
}, [isDemo]); // isDemo만 의존성으로 가짐
해결책
실시간으로 타이머 값을 확인하는 두 번째 useEffect 내부의 setTimeLeft 함수에서 조건을 확인하도록 변경했습니다:
// 해결된 코드
useEffect(() => {
if (!isDemo || timeLeft <= 0) return;
const interval = setInterval(() => {
setTimeLeft(prev => {
if (prev <= 590) { // 매초마다 이 조건이 확인됨!
clearInterval(interval);
setShowTimeoutModal(true);
return prev;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}, [isDemo, timeLeft]); // timeLeft 변화에 반응
6. useEffect 정리(Cleanup) 함수
useEffect는 정리 함수를 반환할 수 있습니다. 이 함수는 컴포넌트가 언마운트되거나 다음 이펙트가 실행되기 전에 호출됩니다:
useEffect(() => {
const timer = setInterval(() => {
// 타이머 로직
}, 1000);
// 정리 함수: 메모리 누수 방지
return () => clearInterval(timer);
}, []);
정리 함수는 메모리 누수를 방지하는 데 중요합니다. 특히 타이머나 이벤트 리스너와 같은 리소스를 사용할 때 반드시 정리해주어야 합니다.
7. 핵심 요약
- useEffect 실행 시점은 의존성 배열에 의해 결정됩니다.
- 상태 업데이트는 즉시 일어나지만, 화면 갱신은 다음 렌더링에서 발생합니다.
- 함수형 업데이트(
prev => {...}
)는 이전 상태에 의존하는 업데이트를 안전하게 처리합니다. - 의존성 배열 설계는 컴포넌트의 올바른 동작과 성능에 중요합니다.
- 정리 함수로 타이머나 이벤트 리스너와 같은 리소스를 해제해야 합니다.
오늘 배운 내용을 통해 React에서 타이머 같은 부수 효과를 다룰 때 useEffect와 상태 관리의 중요성을 이해할 수 있었습니다. 의존성 배열을 올바르게 설정하고 함수형 업데이트를 활용하면 더 안정적인 React 애플리케이션을 구축할 수 있습니다.
TIL: 듀티메이트 자동 생성 구독 시스템 구현
오늘 듀티메이트 앱에 자동 생성 구독 시스템을 구현했습니다. 이 과정에서 여러 기술적인 내용과 React 컴포넌트 설계에 대해 배웠습니다. 또한 Patch, Put 메서드의 차이를 알아보고 결정하였습니다.
배운 내용
1. React 모달 구현 패턴
- 여러 모달을 순차적으로 표시하기 위한 상태 관리 방법
- 부모 컴포넌트에서 모달 상태를 관리하고 자식 컴포넌트에 props로 전달하는 패턴
- 모달 닫기 및 다음 모달 열기 로직 설계
2. API 호출 관리
- 서비스 레이어를 통한 API 호출 분리
- API 오류 처리 및 예외 상황 대응
- 개발 환경에서 API 호출 실패 시 대체 로직 구현 (임시 데이터 사용)
3. CORS 이슈 해결
- PATCH 요청시 preflighted request로 인한 CORS 문제 발생
- 단순 요청(GET)과 preflighted 요청의 차이점
- 백엔드 측에서 Access-Control-Allow-Methods 설정 필요성
4. Put vs Patch
PUT
- 정의: 대상 리소스의 상태를 요청에 포함된 표현으로 대체하는 메서드
- 특징:
- 클라이언트가 리소스의 정확한 URI를 알아야 함 (예:
/payments/1
) - 멱등함 (같은 요청을 여러 번 보내도 결과가 동일)
- 리소스 전체를 업데이트해야 함 (모든 필드 데이터 필요)
- 클라이언트가 리소스의 정확한 URI를 알아야 함 (예:
PATCH
- 정의: 요청에 설명된 변경사항을 특정 리소스에 적용하는 메서드
- 특징:
- 특정 리소스 URI를 정확히 알아야 함
- 부분 업데이트 가능 (변경이 필요한 필드만 요청 본문에 포함)
- 일반적으로 멱등하지 않음 (동시 호출 시 데이터 손실 가능)
비교 요약표
메서드 | 설명 | 요청 URI | 멱등성 |
---|---|---|---|
PUT | 리소스 생성 및 전체 업데이트 | 특정 리소스 URI | O |
PATCH | 리소스 부분 업데이트 | 특정 리소스 URI | X |
채널톡 SPA 환경에 적용하기 - React 프로젝트 적용 TIL
오늘 React 프로젝트에 채널톡을 적용하는 과정을 진행했습니다. 채널톡은 고객 소통 및 지원 플랫폼으로, 웹사이트에 채팅 기능을 쉽게 추가할 수 있게 해주는 서비스입니다.
학습 내용
1. SPA vs MPA의 차이점
- MPA(Multi-Page Application): 각 페이지를 요청할 때마다 새로운 정적 리소스를 로드하는 방식
- SPA(Single Page Application): 최초 한 번만 페이지를 로드하고, 이후에는 필요한 데이터만 서버에서 가져와 동적으로 페이지를 갱신하는 방식
- React는 SPA 프레임워크이기 때문에 MPA와는 다른 방식으로 채널톡을 설치해야 함
2. 채널톡 서비스 클래스 생성
- SPA 환경에서 채널톡을 사용하기 위해 별도의 서비스 클래스를 생성
- TypeScript 사용 시 인터페이스도 함께 정의됨
3. 채널톡 초기화 과정
- loadScript(): 채널톡 스크립트를 로드하는 함수
- boot(): 채널톡 서비스를 초기화하는 함수, 사용자 정보와 함께 호출 가능
4. 컴포넌트 분리를 통한 구조화
App.tsx
에 직접 채널톡 코드를 작성하는 대신, 별도의 컴포넌트(ChannelTalkLoader
)를 생성하여 관심사 분리- 이를 통해 코드 가독성과 유지보수성 향상
5. 사용자 인증 정보 연동
- Zustand 상태 관리 라이브러리를 사용해 관리되는 사용자 인증 정보를 채널톡에 연동
- 로그인 상태에 따라 익명 사용자 또는 인증된 사용자로 채널톡 초기화
isAuthenticated
와userInfo
상태에 따라 조건부 초기화 설정
6. 의존성 배열과 useEffect
useEffect
의 의존성 배열에isAuthenticated
와userInfo
를 추가하여 로그인 상태 변화에 따라 채널톡이 재초기화되도록 설정
결론
react 프로젝트에 서드파티 프로그램을 이식하는 과정을 처음 겪어 보았고, 해당 과정에서 서드파티 프로그램과 데이터를 주고받는 방식에 대한 이해도를 높일 수 있었습니다.
'Project' 카테고리의 다른 글
[JPA] entity의 cascade 와 db의 on delete cascade 차이 이해하기 (1) | 2025.05.06 |
---|---|
[JPA] N+1문제 정의 + 해결 전략 (0) | 2025.02.15 |
[JPA] API 서비스 흐름 알아보기. (0) | 2025.02.02 |
[JPA] Entity 설계하기. (1) | 2025.01.27 |
[프로젝트 Day 5] OAuth2 로그인 (Google) (0) | 2024.11.19 |