📌 useEffect()
: 리액트 컴포넌트와 외부 시스템을 동기화할 때 사용
- 렌더링 자체에 의해 발생하는 부수 효과를 특정하는 것
- 특정 이벤트가 아닌 렌더링에 의해 직접 발생한다.
(어떤 상호작용과도 상관없이 발생, 커밋 단계 이후 실행 됨) - React는 화면을 업데이트한 다음 useEffect 내부의 코드를 실행한다.
➡️ useEffect는 화면에 렌더링이 반영될 때까지 코드 실행을 지연 시킨다. - 외부 시스템(external)
: React에서 제어되지 않는 시스템
(ex. 네트워크, 브라우저 API, 서드파티 라이브러리와의 연결, 데이터 가져오기, DOM 수정, 타이머 설정, 구독 등)
- ex) 서버에 접속하는 것
➡︎ 순수한 계산이 아니고 부수 효과를 발생시키기 때문에 렌더링 중에는 할 수 없다❌
➡︎ 이벤트도 아니다❌
👉 이펙트(Effects) 사용⭕
- ex) 서버에 접속하는 것
- 컴포넌트
- 렌더링 ➡︎ 순수 함수
- 이벤트(사용자 액션 O) ➡︎ 이벤트 핸들러
- 부수 효과 (사용자 액션 X) ➡︎ Effect 함수
useEffect(setup, dependencies?)
- 매개변수
- setup
: Effect 로직이 포함된 설정 함수
- clean up(정리) 함수를 반환
- DOM 커밋 이후 시점에서 실행
- 상태가 업데이트 될때마다 실행
- clean up(정리) 함수를 반환
- dependencies
: 의존성(종속성) 배열
- setup
⏩ 사용
1. Effect 불러오기
- 기본적으로 Effect는 모든 commit 이후에 실행된다.
import { useEffect } from 'react';
2. Effect 선언하기
- 컴포넌트의 최상위 레벨에서 호출
- 부수 효과를 렌더링 연산에서 분리하기 위해 useEffect로 감싼다.
function 컴포넌트명() {
useEffect(() => {
//...
});
return (
);
}
3. 의존성 배열(dependency array) 지정
- useEffect가 언제 실행될지를 결정하는 데 사용
👉 Effect를 불필요하게 다시 실행하지 않도록 지시하기 위해 설정 - 배열에 포함된 변수들(useEffect가 의존하는 값들)이 변경될 때마다 useEffect는 다시 실행된다.
- 의존성 배열에 지정된 값이 이전 렌더링과 동일한지 비교하고, 동일한 값이면 Effect를 다시 실행하지 않는다.
useEffect(() => {
// ...
}, [dependency]);
✨ 의존성 배열이 없는 경우와 빈 [] 의존성 배열이 있는 경우
// 모든 렌더링 후에 실행
useEffect(() => {
// ...
});
// 처음 한 번만 실행(마운트될 때, 컴포넌트가 나타날 때)
useEffect(() => {
// ...
}, []);
// 마운트될 때 실행, 렌더링 이후에 a 또는 b 중 하나라도 변경된 경우에도 실행
useEffect(() => {
// ...
}, [a, b]);
4. 클린업 함수(cleanup function) 추가
- Effect는 수행 중이던 작업을 취소, 정리하는 방법을 지정해야 한다.
ex) 연결 ↔️ 연결 해제 / 구독 ↔️ 구독 취소 / 불러오기(fetch) ↔️ 취소
- 이벤트 리스너: addEventListener() ↔️ removeEventListener()]
- 타이머: setInterval() ↔️ clearInterval()
- 네트워크 요청: AbortController() ↔️ abort()
- React는 Effect가 다시 실행되기 전마다 클린업 함수를 호출하고, 컴포넌트가 마운트 해제(제거)될 때에도 마지막으로 호출한다.
function 컴포넌트명() {
useEffect(() => {
//...
return () => {
// 클린업(clean up) 함수
};
}, []);
return (
<div />
);
}
✅ 렌더링 이슈
⏩ 이펙트(Effect) 내부에서 실행되는 함수
: 이 함수는 useEffect 안에서만 사용되기 때문에, 이펙트 외부의 상태나 변수를 참조하지 않는다.
- 이런 함수들은 이펙트가 리렌더링될 때마다 새로 만들어져도 큰 문제가 되지 않기 때문에
굳이 메모이제이션(= useCallback 사용)할 필요는 없다. - 종속성 배열에 포함할 필요가 없다.
useEffect(() => {
const logMessage = () => {
console.log('Effect is running');
};
logMessage();
}, []); // logMessage는 useEffect 내부에 있으므로 종속성 배열에 포함할 필요가 없음
⏩ 이펙트(Effect) 외부에 있는 함수
: 이 함수가 상태나 다른 값을 참조하는 경우, 리렌더링 시에 해당 함수가 변할 수 있다.
- 이 함수가 변하면 useEffect는 다시 실행되어 잦은 리-렌더링을 유발할 수 있다.
- 만약 함수가 이펙트 외부에서 정의되어 있고, 리렌더링 시에 함수가 변할 가능성이 있다면,
1) useCallback을 사용하여 메모이제이션하거나
2) 종속성 배열에 포함해야 한다.
3) 가능한 경우 이펙트 내부에 함수를 포함하는 것이 더 좋다.
const fetchData = () => {
// 데이터 fetch 로직
};
useEffect(() => {
fetchData();
}, [fetchData]); // fetchData가 외부에 있으므로 종속성 배열에 포함되어야 함
📢 이벤트(Event) vs 이펙트(Effect)
이벤트(Event) | 이펙트(Effect) | |
동작 시점 | 사용자의 상호작용 시 즉각적으로 발생 | 컴포넌트가 렌더링된 후 또는 상태가 변경된 후 발생 |
주요 목적 | 유저 상호작용 처리 (클릭, 키 입력 등) | 비동기 작업, 사이드 이펙트 처리 (API 호출, 타이머 등) |
바인딩 위치 | DOM 요소에 직접 연결 (onClick, onChange) |
컴포넌트의 렌더링 후 발생하며, 리액트 컴포넌트 내부에서 처리 |
실행 타이밍 | 즉각적인 실행 | 렌더링 완료 후 비동기적으로 실행 |
사용 사례 | 클릭, 키보드 입력, 마우스 이동 등 | 데이터 가져오기, 타이머 설정, 구독, 외부 자원 접근 등 |
반환 값 | 보통 아무 것도 반환하지 않음❌ | 클린업 함수 반환(이전 사이드 이펙트 정리) |
반응 대상 | 유저의 직접적 행동 | 컴포넌트의 상태 변화, props 변경 |
클린업 필요 |
보통 클린업 불필요❌ | 클린업 작업을 통해 메모리 누수 방지⭕ |
useEffect – React
The library for web and native user interfaces
ko.react.dev
Effect로 동기화하기 – React
The library for web and native user interfaces
ko.react.dev