React.js - 라이프사이클, useEffect 사용하기, useEffect로 라이프사이클 제어하기
라이프사이클이란?
사람의 생애주기같이, 컴포넌트에도 라이프사이클이 있다. mount, update, unmount 순서로 흘러간다.

- Mount : 컴포넌트가 처음으로 렌더링 되었을 때
- Update : 컴포넌트가 리렌더링 되었을 때
- UnMount : 컴포넌트가 화면에서 사라질 때
useEffect 사용하기
import "./App.css";
import Viewer from "./components/Viewer";
import Controller from "./components/Controller";
import { useState, useEffect } from "react";
function App() {
const [count, setCount] = useState(0);
const [input, setInput] = useState("");
useEffect(() => {
console.log(`count: ${count} / input: ${input}`);
}, [count, input]);
// 의존성 배열
// dependency array
// deps
const onClickButton = (value) => {
setCount(count + value);
};
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input
value={input}
onChange={(e) => {
setInput(e.target.value);
}}
/>
</section>
<section>
<Viewer count={count} />
</section>
<section>
<Controller onClickButton={onClickButton} />
</section>
</div>
);
}
export default App;
useEffect라는 훅을 이용해서 컴퍼넌트의 사이드 이펙트를 만들거나 제어할 수 있다. 여기서 사이드 이펙트란, 컴포넌트의 동작에 따라 파생되는 여러 효과들을 말한다.
우리는 count, input의 state 값이 바뀌면 해당 값을 콘솔에 출력하는 사이드 이펙트를 만들려고 한다. useEffect를 리액트에서 임포트 해오고, useEffect(()=>{}, []) 로 선언한다. 두 번째 매개변수인 배열에 들어있는 값이 변하면 첫 번째 매개변수인 화살표 함수가 실행된다. 이 배열을 우리는 의존성 배열, 영어로는 deps 라고 부른다.
여기서 한 가지 의문점이 들 수 있다. 그냥 setCount 함수 뒤에 콘솔로 변화한 값을 출력하면 될 걸 왜 굳이 useEffect라는 훅을 사용할까? 그 이유는 바로 리액트의 상태 변화 함수는 비동기로 동작하기 때문이다. 여기서 비동기란, 바로 실행되지 않고 뒤늦게 완료되는 것을 말한다. 그렇기 때문에 setCount 함수가 완료되기 전에 콘솔을 출력하면 변화하기 전의 값이 출력된다. 즉 리액트의 state는 비동기로 업데이트가 되기 때문에, 변경된 state 값을 바로 이용하기 위해서는 useEffect를 사용해야 한다.
useEffect로 라이프사이클 제어하기
// App.jsx
import "./App.css";
import Viewer from "./components/Viewer";
import Controller from "./components/Controller";
import Even from "./components/Even";
import { useState, useEffect, useRef } from "react";
function App() {
const [count, setCount] = useState(0);
const [input, setInput] = useState("");
const isMount = useRef(false);
// 1. 마운트 : 탄생
useEffect(() => {
console.log("mount");
}, []);
// 2. 업데이트 : 변화, 리렌더링
useEffect(() => {
if (!isMount.current) {
isMount.current = true;
return;
}
console.log("update");
});
// 3. 언마운트 : 죽음
const onClickButton = (value) => {
setCount(count + value);
};
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input
value={input}
onChange={(e) => {
setInput(e.target.value);
}}
/>
</section>
<section>
<Viewer count={count} />
{count % 2 === 0 ? <Even /> : null}
</section>
<section>
<Controller onClickButton={onClickButton} />
</section>
</div>
);
}
export default App;
// Even.jsx
import { useEffect } from "react";
const Even = () => {
useEffect(() => {
//클린업, 정리함수
return () => {
console.log("unmount");
};
}, []);
return <div>짝수입니다</div>;
};
export default Even;
컴포넌트의 사이드 이펙트에는 라이프 사이클 제어 포함되어 있다. 마운트, 업데이트, 언마운트 될 때 각각 useEffect를 어떻게 사용하는지 알아보자.
- 마운트 시에는 deps에는 아무 값도 넣어주지 않는다. useEffect는 deps에 있는 값이 변화해야만 실행되기 때문에 처음 mount될 때 단 한 번만 실행된다.
- 업데이트 시에는 deps를 생략해준다. 그러면 컴포넌트가 리렌더링 될 때마다 알아서 useEffect가 실행된다.
- 언마운트 시에는 콜백 함수에서 함수를 반환하는 리턴문을 작성해준다. 이 리턴문은 useEffect 함수가 종료될 때, 즉 언마운트 될 때 실행된다.