오늘은 React에서 정말정말 자주 쓰이는 useEffect hook에 대해서 알아보겠습니다.
useEffect hook은 클래스 컴포넌트에서 componentDidMount, componentDidUpdate, componentWillUnmount로 컴포넌트의 생명주기를 관리하던 것을 함수형 컴포넌트에서 수행할 수 있게 하고,특정 상태나 속성(props)의 변화에 따라 부수 효과(side effects)를 관리하는 훅인데요.
차근차근 살펴보겠습니다.
0. useEffect는 왜 필요할까?
리액트 컴포넌트는 화면에 보여주고 싶은 것을 그리는 역할을 합니다. 그런데 때로는 화면을 그리는 것 외에 다른 작업들이 필요해요.
예를 들어,
- 데이터 가져오기 (API 호출): 웹사이트에 접속하면 서버에서 최신 게시글 목록을 가져와야겠죠?
- 구독/구독 해지: 실시간 채팅 앱이라면 새로운 메시지가 오는지 계속 지켜봐야 하고, 앱을 닫으면 더 이상 지켜볼 필요가 없겠죠?
- 수동으로 DOM 조작: 리액트는 가상 DOM을 사용하지만, 때로는 특정 라이브러리 연동 등을 위해 실제 DOM에 직접 접근해야 할 때도 있습니다.
- 타이머 설정: 일정 시간마다 어떤 작업을 반복하고 싶을 때.
이렇게 '화면을 그리는 것 외의 작업'들을 리액트에서는 '부수 효과(Side Effect)'라고 하는데요. 그리고 이 부수 효과를 컴포넌트 안에서 안전하게 다룰 수 있도록 도와주는 것이 바로 useEffect 훅입니다.
1. useEffect 기본 사용법
useEffect의 기본 사용법은 다음과 같습니다.
useEffect(() => {
// 여기가 부수 효과를 처리하는 코드 블록
}, [의존성 배열]); // 선택 사항: 의존성 배열
첫 번째 인자에는 함수를 전달하며, 이 안에 우리가 실행하고 싶은 부수 효과 코드를 작성합니다.
두 번째 인자에는 의존성 배열을 전달하는데, 이 배열 안에 있는 값들이 변경될 때만 첫 번째 인자의 함수가 다시 실행됩니다.
2. 컴포넌트 생명주기별 useEffect 사용 사례
지난 글에서 함수형 컴포넌트의 생명주기에 대해서 다룬 적 있는데요. useEffect가 어떻게 컴포넌트 생명주기와 연결되는지 살펴볼까요?
https://musubi-iroiro.tistory.com/630
[React] React 함수형 컴포넌트의 생명주기에 대해 araboza.
안녕하세요! 오늘은 함수형 컴포넌트의 생명주기(life cycle)을 따라가며, 그들이 언제 태어나고(마운트), 성장하고(업데이트), 그리고 사라지는지(언마운트)에 대해 알아보겠습니다.🚀 1. 컴포넌
musubi-iroiro.tistory.com
안 읽어보셨던 분들은 한번 읽어보시고요~!
요약해보면, 컴포넌트는 마운트(컴포넌트가 처음으로 화면에 나타날 때), 업데이트(컴포넌트의 상태나 속성이 변경되어 화면이 다시 그려질 때), 언마운트(컴포넌트가 화면에서 사라질 때)의 생명주기를 갖는데요. useEffect는 이 세 가지 생명주기에 걸쳐 부수 효과를 제어할 수 있습니다.
1️⃣사용법 1. 먼저, 마운트 시 한 번만 실행하고 싶은 경우 : 두 번째 인자에 빈 배열을 전달!
useEffect(() => {
console.log('컴포넌트가 화면에 처음 나타났어요!');
// 여기서 API 호출 등을 할 수 있습니다.
}, []); // 빈 배열!
두 번째 인자로 빈 배열([])을 넘겨주면, useEffect 안의 코드는 컴포넌트가 맨 처음 화면에 나타날 때 (마운트 될 때) 딱 한 번만 실행됩니다. 마치 componentDidMount와 같은 역할을 한다고 생각하시면 쉬워요. API 호출 등 초기 데이터를 불러올 때 유용하게 사용됩니다.
2️⃣ 사용법 2. 특정 값이 변할 때마다 실행하고 싶은 경우 : 두 번째 인자에 의존성 배열을 전달!
import React, { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`카운트가 ${count}로 변경되었어요!`);
// count 값이 변경될 때마다 이 코드가 실행됩니다.
}, [count]); // count가 의존성 배열에 있습니다.
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
export default Counter;
요렇게 의존성 배열에 count와 같은 특정 값을 넣어주면, count 값이 변경될 때마다 useEffect 안의 코드가 다시 실행됩니다. 이는 componentDidUpdate와 비슷한 역할을 합니다. 예를 들어, 사용자 ID가 변경될 때마다 새로운 사용자 정보를 불러와야 한다면 이 방식을 사용하면 되겠죠?
3️⃣ 사용법 3. 정리 작업(clean up)을 수행하고 싶을 때 : 첫번째 인자에 함수를 return!
때로는 부수 효과가 끝난 후 뒷정리가 필요할 때가 있습니다. 예를 들어, 타이머를 설정했다면 컴포넌트가 사라질 때 타이머를 해제해줘야 메모리 누수를 방지할 수 있습니다. useEffect는 이럴 때 함수를 반환(return)하는 방식으로 정리 작업을 할 수 있도록 해줍니다.
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);
// cleanup 함수를 반환합니다.
return () => {
console.log('타이머가 정리되고 있어요!');
clearInterval(interval); // 컴포넌트가 언마운트될 때 타이머를 해제합니다.
};
}, []); // 마운트 시 한 번만 실행되도록 빈 배열
return (
<div>
<p>경과 시간: {seconds}초</p>
</div>
);
}
export default Timer;
useEffect 안에서 함수를 반환하면, 이 반환된 함수는 컴포넌트가 언마운트될 때, 그리고 다음 useEffect가 실행되기 전 (즉, 의존성 배열의 값이 변경되어 useEffect가 다시 실행될 때)에도 이전 부수 효과를 정리하기 위해 실행됩니다.
이는 componentWillUnmount와 componentDidUpdate의 특정 상황에 해당한다고 볼 수 있겠죠?
3. useEffect 사용 시 주의사항
이렇게 엄청 유용한 hook이지만, useEffect를 사용할 때는 주의할 점들이 좀 있습니다.
- 무한 루프 조심하기!: 의존성 배열에 변화하는 값을 제대로 넣지 않으면 무한 루프에 빠질 수 있습니다. 예를 들어, useEffect 안에서 상태를 업데이트하는데, 그 상태가 의존성 배열에 있다면 계속해서 useEffect가 호출될 수 있습니다.
- 필요한 의존성만 넣기!: 의존성 배열에 너무 많은 값을 넣으면 불필요하게 useEffect가 자주 실행될 수 있습니다. 정말로 그 값이 변할 때만 다시 실행되어야 하는지 고민하고 넣어주세요.
- 비동기 처리 관련: useEffect 안에서 async/await를 직접 사용할 수 없습니다. 비동기 함수를 정의하고 그 함수를 useEffect 안에서 호출하는 방식으로 사용해야 합니다.
이상입니다.
읽어주셔서 감사합니다!
'웹개발 > ReactJS' 카테고리의 다른 글
[React] React의 전역 상태 관리 (0) | 2025.06.29 |
---|---|
[React] React Compiler 당장 씁시다 (0) | 2025.06.20 |
[React] 메모이제이션으로 성능 최적화하기(useMemo, React.memo, useCallback 완전 비교) (1) | 2025.06.19 |
[React] useRef hook에 대해 araboza (1) | 2025.06.19 |
[React] useReducer hook에 대해 araboza (1) | 2025.06.13 |