useEffect
useEffect는 React 컴포넌트에서 사이드 이펙트를 처리하는 Hook이다.
💡 사이드 이펙트
사이드 이펙트란 컴포넌트가 화면을 렌더링하는 작업 외에, 컴포넌트의 동작에 따라 추가로 실행되는 작업을 의미한다.
라이프사이클의 특정 시점에 실행하는 작업도 사이드 이펙트로 볼 수 있다.
- 컴포넌트가 처음 화면에 나타났을 때 콘솔 출력하기
- 특정 state 값이 변경되었을 때 작업 실행하기
- 서버에서 데이터 불러오기
- 타이머 설정하기
- 이벤트 리스너 등록하기
- 컴포넌트가 사라질 때 정리 작업하기
useEffect 기본 문법
useEffect(() => {
// 실행할 작업
}, [의존성 배열]);첫 번째 인수에는 실행할 콜백 함수를 전달하고, 두 번째 인수에는 의존성 배열을 전달한다.
// useEffect(콜백함수, [의존성 배열]);
useEffect(() => {}, [count]);의존성 배열은 Dependency Array라고 하며, 줄여서 deps라고 부르기도 한다.
의존성 배열에 어떤 값을 넣느냐에 따라 useEffect가 실행되는 시점이 달라진다.
useEffect 실행 시점
useEffect는 의존성 배열에 따라 크게 세 가지 방식으로 실행된다.
1. 렌더링될 때마다 실행
useEffect(() => {
console.log("렌더링될 때마다 실행");
});이 경우 컴포넌트가 처음 렌더링될 때도 실행되고, state나 props가 변경되어 다시 렌더링될 때도 실행된다.
2. 처음 한 번만 실행
의존성 배열에 빈 배열 []을 넣으면 컴포넌트가 처음 렌더링된 후 한 번만 실행된다.
useEffect(() => {
console.log("Mount");
}, []);이 방식은 컴포넌트가 처음 화면에 나타나는 마운트 시점에 실행할 작업을 작성할 때 사용한다.
예를 들어 다음과 같은 작업에 사용할 수 있다.
- 초기 데이터 요청
- 초기 설정
- 외부 라이브러리 초기화
- 컴포넌트가 처음 나타났을 때 콘솔 출력
3. 특정 값이 변경될 때 실행
의존성 배열에 특정 값을 넣으면 해당 값이 변경될 때마다 실행된다.
useEffect(() => {
console.log(`count: ${count}`);
}, [count]);위 코드는 count 값이 변경될 때마다 실행된다.
즉, 의존성 배열에 들어간 값이 변경되면 useEffect의 콜백 함수가 다시 실행된다.
useEffect와 라이프사이클
React 컴포넌트의 라이프사이클은 크게 세 단계로 나눌 수 있다.
- Mount → 컴포넌트가 처음 화면에 나타남
- Update → state나 props 변경으로 다시 렌더링됨
- Unmount → 컴포넌트가 화면에서 사라짐
함수 컴포넌트에서는 useEffect를 사용해 이 라이프사이클 흐름을 제어할 수 있다.
1. Mount 제어하기
Mount는 컴포넌트가 처음 화면에 나타나는 단계이다.
useEffect(() => {
console.log("Mount");
}, []);의존성 배열에 빈 배열 []을 넣었기 때문에 이 코드는 컴포넌트가 처음 렌더링된 후 한 번만 실행된다.
import { useEffect } from "react";
function App() {
useEffect(() => {
console.log("Mount");
}, []);
return <div>App</div>;
}
export default App;이처럼 컴포넌트가 처음 나타났을 때 실행하고 싶은 작업은 빈 배열을 사용해 작성할 수 있다.
2. Update 제어하기
Update는 컴포넌트가 다시 렌더링되는 단계이다.
컴포넌트는 다음과 같은 경우 업데이트된다.
- state가 변경될 때
- props가 변경될 때
- 부모 컴포넌트가 다시 렌더링될 때
의존성 배열을 생략하면 렌더링될 때마다 useEffect가 실행된다.
useEffect(() => {
console.log("Update");
});하지만 이 코드는 처음 마운트될 때도 실행된다.
처음 렌더링은 제외하고, 업데이트될 때만 실행하고 싶다면 useRef를 함께 사용할 수 있다.
import { useEffect, useRef, useState } from "react";
function App() {
const [count, setCount] = useState(0);
const isMounted = useRef(false);
useEffect(() => {
if (!isMounted.current) {
isMounted.current = true;
return;
}
console.log("Update");
});
return <button onClick={() => setCount(count + 1)}>count: {count}</button>;
}
export default App;- 컴포넌트가 처음 렌더링된다.
useEffect가 실행된다.isMounted.current가false이므로true로 변경하고 종료한다.- 이후
state가 변경되어 다시 렌더링된다. - 이제
isMounted.current가true이므로 "Update"가 출력된다.
useRef는 값이 변경되어도 컴포넌트를 다시 렌더링하지 않는다.
그래서 마운트 여부를 기억하는 용도로 사용할 수 있다.
3. Unmount 제어하기
Unmount는 컴포넌트가 화면에서 사라지는 단계이다.
useEffect(() => {
return () => {
console.log("Unmount");
};
}, []);useEffect의 콜백 함수에서 함수를 return하면, 이 함수는 클린업 함수 또는 정리 함수가 된다.
클린업 함수는 컴포넌트가 화면에서 사라질 때 실행된다.
import { useEffect } from "react";
const Even = () => {
useEffect(() => {
return () => {
console.log("UnMount");
};
}, []);
return <p>짝수입니다.</p>;
};
export default Even;이 컴포넌트는 화면에 나타날 때는 <p>짝수입니다.</p>를 렌더링한다.
그리고 컴포넌트가 화면에서 사라질 때 useEffect의 정리 함수가 실행되면서 "UnMount"가 출력된다.
정리
💡 useEffect는 React 컴포넌트에서 사이드 이펙트를 처리하는 Hook이다.
컴포넌트가 렌더링된 이후 실행할 작업을 작성할 수 있고, 의존성 배열을 통해 실행 시점을 제어할 수 있다.
의존성 배열 없음→ 렌더링될 때마다 실행빈 배열 []→ 처음 한 번만 실행[count]→ count가 변경될 때마다 실행return함수 → 컴포넌트가 사라질 때 정리 작업 실행
라이프사이클 관점에서는 다음과 같이 이해할 수 있다.
- Mount →
useEffect(() => {}, []) - Update →
useEffect(() => {}) - Unmount →
useEffect(() => { return () => {} }, [])