[React] #2. useEffect를 이용해 Life Cycle 제어하기
useEffect
리액트의 useEffect는 리액트 훅(React Hook)의 일종으로, 리액트의 Side Effect를 처리합니다.
여기서 Side Effect란 데이터 로드, 구독 설정 등의 작업 뿐만 아니라, 컴포넌트의 라이프 사이클 제어까지 포함합니다.
Life Cycle은 일반적으로 Mount, Rerend, Unmount 의 단계를 가지며, 쉽게 비유하자면 웹페이지 상에서 생성, 변경, 삭제 로 이해하면 됩니다. 이 과정에 대한 제어를 useEffect를 사용해서 수행할 수 있습니다.
import { useEffect } from 'react';
function App() {
useEffect(()=>{
console.log("콜백함수 부분")
...
},[ ]) //의존성 배열 부분
return (
...
);
}
useEffect는 위와 같은 형태를 가집니다.
기본적으로 콜백함수와 의존성 배열(Deps)를 매개변수로 가지며, 의존성 배열의 내용에 따라서 useEffect의 실행 시점을 제어할 수 있습니다.
1. 컴포넌트 마운트 시 실행
import React, { useEffect } from 'react';
function ExampleComponent() {
useEffect(() => {
console.log('Component is mounted'); // 컴포넌트가 마운트될 때 수행
return () => {
console.log('Component is unmounted'); // 언마운트 될 때 실행
};
}, []); // Deps를 비워두면 컴포넌트가 처음 마운트될 때만 실행
return (
<div>
<p>content</p>
</div>
);
}
useEffect의 Deps를 비워두면 컴포넌트가 처음 마운트될 때만 useEffect의 콜백함수 부분이 실행됩니다.
위의 코드에서 컴포넌트가 마운트되면 콘솔에 'Component is mounted' 가 찍히고,
컴포넌트 마운트를 해제(useEffect의 return)하면서 'Component is unmounted'를 출력하게 됩니다.
2. 상태(의존성)가 변경 시 실행
import React, { useEffect, useState } from 'react';
function ExampleComponent() {
const [data, setData] = useState('');
useEffect(() => {
console.log('Data has changed:', data); // data 상태가 변경될 때 수행할 작업
}, [data]); // data가 변경될 때만 실행됨
return (
<div>
<p>Data: {data}</p>
<button onClick={() => setData('New Data')}>
Change Data
</button>
</div>
);
}
useEffect의 Deps에 State를 넣을 수 있습니다. 모든 State를 넣어서 useEffect가 모든 상태 변화로 제어되도록 할 수도 있고, 일부 State만 넣어서 특정 상태 변화에만 제어되도록 할 수 있습니다.
위의 코드에서 Deps에 Data라는 상태를 넣어서, Data 상태가 변함에 따라 useEffect가 실행되도록 합니다.
기본적으로 컴포넌트 마운트 시, 그리고 State의 변경 시에 콜백함수 부분이 실행됩니다.
useEffect의 내에 return 문이 존재하지 않음으로 마운트 해제 시에는 동작하지 않습니다.
3. 컴포넌트 언마운트 시 실행
import React, { useEffect } from 'react';
function ExampleComponent() {
useEffect(() => {
return () => { //컴포넌트가 언마운트될 때 실행되는 부분
console.log('Component is unmounted');
};
}, []); // 빈 의존성 배열 -> 컴포넌트가 처음 마운트될 때 실행됨
return (
<div>
<p>Component content</p>
</div>
);
}
위의 코드는 콜백함수 부분이 존재하지 않지만, 빈 Deps를 가지고 있고 useEffect 내에 return 문을 가지고 있습니다.
따라서 컴포넌트 마운트 시, 컴포넌트 언마운트 시 실행됩니다.
컴포넌트 언마운트시 실행하려면 Deps를 빈 배열로 두고, return 문에 따른 동작을 추가하면 되는 것입니다.
이렇게 하는 이유는 Deps 안에 있는 State의 변경에 따라 콜백함수가 호출되는데,
Deps가 비어있을 경우 콜백함수는 최초 마운트시에만 한번 실행이 되기 때문입니다.
4. 컴포넌트 마운트시 실행하지 않기
import React, { useEffect, useRef, useState } from 'react';
function ExampleComponent() {
const [myState, setMyState] = useState('');
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) { // 컴포넌트가 처음 마운트될 때 작업을 수행하지 않음
isFirstRender.current = false;
return;
}
console.log('myState has changed:', myState); // myState가 변경될 때만 실행될 작업
}, [myState]); // myState가 변경될 때 실행됨
return (
<div>
<p>myState: {myState}</p>
<button onClick={() => setMyState('New State')}>
Change myState
</button>
</div>
);
}
컴포넌트가 마운트될 때 실행하지 않는 방법입니다. 이는 useRef를 이용할 수 있습니다.
useRef는 DOM 요소에 접근하거나 인스턴스 변수를 참조하기 위해 사용하는 Hook 입니다.
자세한 설명은 다른 게시글로 작성하겠습니다.
useRef는 DOM 요소 접근 뿐만 아니라, 변수처럼 값을 저장해 사용할 수도 있습니다.
위의 코드에선 current 프로퍼티에 'true' 라는 값을 할당하고 있습니다.
이를 useEffect 내에서 참조하여 useRef의 current 프로퍼티가 true라면, 콜백함수 부분을 종료하게 됩니다.
다시 말해서, useEffect는 기본적으로 마운트 될 때 실행되지만, 콜백함수 부분에서 True와 False를 통해 아래 내용을 실행할지 또는 바로 종료할지 결정하는 것입니다. 일종의 Flag 변수인 셈입니다.
요약하자면, 아래와 같습니다.
- useEffect는 Side Effect를 제어한다.
- useEffect로 컴포넌트의 Life Cycle을 제어할 수 있다.
- 의존성 배열의 내용에 따라 컴포넌트의 리렌더링을 제어할 수 있다.
- useEffect 내의 return 문을 통해 언마운트 될 때의 작업을 수행할 수 있다.
- useEffect와 useRef를 사용해, 초기 마운트 시 작업을 제어할 수 있다.
처음엔 굉장히 어려운 개념처럼 느껴졌으나, Life Cycle 이라는 측면에서 이해하니 굉장히 효율적인 훅이라는 생각이 들었씁니다.