react.js 를 공부하면서 useEffect의 사용법에 대해 간략히 정리하는 글이다.
useEffect 에 대해 정리하기 이전에 react 컴포넌트의 Lifecycle(생명주기) 부터 짚고 넘어가야할 필요가 있다.
- React Component Lifecycle(생명주기)
react 컴포넌트의 생명주기는 위와 같이 크게 Mount, Update, Unmount 3가지로 나눌 수 있다.
1. Mount
컴포넌트가 최초로 렌더링되어 화면에 나타나는 것을 말하는데 이때 초기화 작업등의 특정 작업을 수행하고 싶다면 ComponetDidMount 메소드를 사용하면 mount 되는 시점에 작업을 수행할 수 있다.
2. Update
컴포넌트내에서 관리하는 state 나 props가 바뀌어 리렌더링 되는 것을 말하는데 이때 예외처리작업등의 특정 작업을 수행하고 싶다면 ComponentDidUpdate 메소드를 사용하면 리렌더링이 될 때마다 특정작업을 수행할 수 있다.
3. Unmount
컴포넌트가 ummount 되어 화면에서 없어지는 시점을 말하며 이때 메모리정리작업등의 특정작업을 수행하고 싶을때 componentWillMount 메소드를 사용하면 된다.
앞서 말한 3가지의 lifecycle 종류별 실행시킬수 있는 ComponetDidMount, ComponentDidUpdate, ComponentWillMount는 클래스형 컴포넌트에서만 사용이 가능하다. 그 외에 앞서 공부했던 state나 ref등의 기능들도 클래스형 컴포넌트에서만 사용이 가능했었는데 이러한 기능들을 함수형 컴포넌트에서도 사용이 가능하게 끔 해주는 것이 바로 React Hooks 이다. useEffect도 React Hooks중의 하나인데 컴포넌트의 lifecycle별 사용했던 메소드의 기능들을 사용 가능하게 해준다. 앞서 공부했던 useState, useRef도 모두 Hook 이다.
클래스형 컴포넌트에서 제공해주는 메소드를 두고 굳이 ReactHooks를 사용하는 이유는 클래스형 컴포넌트는 기능이 추가 될때 마다 길어지는 코드 문제, 중복코드, 가독성등의 문제로 인해 요 근래에는 클래스형 컴포넌트보다는 함수형 컴포넌트의 사용을 더 선호하는 편이기 때문이다.
- UseEffect 사용법
import React, { useEffect } from "react";
useEffect를 사용하기 위해 import를 한다.
useEffect(() => {
// todo ..
}, []); // Dependency Array(의존성 배열): 이 배열 내에 들어있는 값이 변화하면 콜백함수가 실행
기본적인 사용법은 위와 같다. 첫번째 인자는 콜백함수 이고 두번째 인자는 의존성 배열로 이 배열 내에 들어있는 값이 바뀌면 콜백함수가 실행된다. 각 lifecycle별 useEffect를 사용법을 위해 아래 예시를 보면
1. Mount(ComponetDidMount)
import React, { useEffect, useState } from "react";
const Lifecycle = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
// 빈 배열을 넘겨주면 Mount 되는 시점에만 실행
useEffect(() => {
console.log("mount");
}, []);
return (
<div style={{ padding: 20 }}>
<div>
{count}
<button onClick={() => setCount(count + 1)}> + </button>
</div>
<div>
<input value={text} onChange={(e) => setText(e.target.value)}/>
</div>
</div>
);
};
export default Lifecycle;
위와 같이 useEffect에 빈 배열을 넘겨주게 되면 최초에 렌더링 될때만 mount가 표출되고 넘겨준 배열에 변화할 값이 없기에 + 버튼을 클릭하거나 input 태그에 글을 입력하여도 mount가 표출되지 않는다.
2. Update(ComponentDidUpdate)
import React, { useEffect, useState } from "react";
const Lifecycle = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
// 빈 배열을 넘겨주면 Mount 되는 시점에 실행
useEffect(() => {
console.log("mount");
}, []);
// 배열을 넘겨주지 않으면 렌더링될때마다 실행
useEffect(() => {
console.log("update");
});
// 배열에 state나 props 넘겨주면 값이 변화할때마다 실행
useEffect(() => {
console.log(`count is update : ${count}`);
if (count > 5) {
alert("count가 5를 넘었습니다. 1로 초기화합니다.");
setCount(1);
}
}, [count]);
// 배열에 state나 props 넘겨주면 값이 변화할때마다 실행
useEffect(() => {
console.log(`text is update : ${text}`);
}, [text]);
return (
<div style={{ padding: 20 }}>
<div>
{count}
<button onClick={() => setCount(count + 1)}> + </button>
<button onClick={() => setCount(count - 1)}> - </button>
</div>
<div>
<input value={text} onChange={(e) => setText(e.target.value)}/>
</div>
</div>
);
};
export default Lifecycle;
위와 같이 배열을 넘겨주지 않으면 렌더링이 될 때마다 update가 콘솔에 출력되는것을 확인할 수 있고 배열에 state나 props를 넘겨주게되면 해당 값이 바뀔때마다 실행이 되는 것을 확인할 수 있다.
3. Unmount(ComponentWillMount)
import React, { useEffect, useState } from "react";
// 콜백함수에서 return을 해줄시 unmount 되는 시점에 실행
const UnmountTest = () => {
useEffect(() => {
return () => {
console.log("unmount!");
};
});
return <div>Unmount Testing Component</div>;
};
const Lifecycle = () => {
const [isVisible, setIsVisible] = useState(false);
const toggle = () => {
setIsVisible(!isVisible);
};
return (
<div style={{ padding: 20 }}>
<div>
<button onClick={toggle}>ON/OFF</button>
{isVisible && <UnmountTest />}
</div>
</div>
);
};
export default Lifecycle;
unmount 시점에 작업을 수행해주기 위해서는 콜백함수에서 return 을 해주면 되는데 위 예시를 처음 on/off 버튼을 클릭했을때 mount되는 시점에는 아무것도 출력되지 않고 다시 버튼을 클릭하여 unmount하는 시점에 출력이 되는 것을 확인할 수 있다.