React에서는 Side Effect를 발생시킬 때는 아래의 두 조건을 충족시켜야 합니다.
1. 렌더링 이후에 발생시켜야 한다.
2. 매 렌더링 이후가 아니라 조건부로 원하는 순간에만 실행시킬 수 있어야 한다.
React에서는 위의 조건을 충족시키면서 Side Effect를 발생 시킬 수 있는useEffect
라는Hook
을 제공해주며, 이를 통해 손쉽게 Side Effect를 발생시킬 수 있습니다.
const App = () => {
const doSideEffect = () => {
// do some side effect
};
doSideEffect();
return <h1>Hello World</h1>;
};
1. side effect가 blocking 합니다.
2. 매 렌더링마다 side effect가 수행됩니다.
자, 위 두 가지 조건을 충족시키면서 발생시키는 것이 가장 좋습니다. 그런데 React에서는 위의 요구사항을 모두 충족시키면서 side effect를 발생시킬 수 있도록 도와주는 useEffect
라는 훅(Hook)이 이미 존재합니다.
UseEffect는 React에서 side effect를 편리하고 안전하게 발생시킬 수 있도록 도와주는 hook입니다.
import { useEffect } from 'react';
const App = () => {
// 코드 생략
// useEffect(콜백 함수);
useEffect(doSideEffect);
return <h1>Hello, Wecoder</h1>;
};
useEffect
의 인자로 전달했습니다.useEffect를 통해 렌더링이 모두 완료된 후 side effect를 실행한다는 요구사항은 충족시켰지만 아직도 매 렌더링마다 side effect가 실행이 된다는 사실은 변함이 없습니다.
사실 useEffect는 콜백 함수 외에 한 가지의 매개 변수를 더 가지고 있습니다. useEffect의 완전한 형태는 아래와 같습니다.
useEffect(콜백 함수, 의존성 배열);
import { useEffect } from 'react'
// 사용법
useEffect(콜백 함수, 의존성 배열);
// 1. 의존성 배열이 전달되지 않았으므로 매 렌더링마다 side effect가 실행된다
useEffect(() => {
// side effect
});
// 2. 의존성 배열이 비어있으므로 최초 한번만 side effect가 실행된다.
useEffect(() => {
// side effect
}, []);
// 3. 첫 번째 렌더링 이후에 side effect를 실행하고
// 그 이후에는 value 값이 변했을 때만 실행한다.
useEffect(() => {
// side effect
}, [value]);
// 4. 첫 번째 렌더링 이후에 side effect를 실행하고
// 그 이후에는 value1, value2 중 하나라도 변하면 side effect를 실행한다.
useEffect(() => {
// side effect
}, [value1, value2]);
컴포넌트가 렌더링 된다.
(최초로 진행되는 렌더링은 브라우저에 처음으로 이 컴포넌트가 보였다는 의미로 mount
라고 표현합니다.)
useEffect 첫 번째 인자로 넘겨준 콜백 함수가 호출된다. (Side Effect)
컴포넌트의 state 또는 props가 변경되었을 경우 리렌더링이 발생한다. (update)
useEffect는 두 번째 인자에 들어있는 의존성 배열을 확인한다
컴포넌트가 더 이상 필요 없어지면 화면에서 사라진다.
(컴포넌트가 브라우저의 화면에서 사라졌다는 의미로 unmount
라고 표현합니다.)
clean up은 무언가를 정리하고 치운다는 의미 입니다.
useEffect hook은 side effect를 clean up 해주는 기능 또한 가지고 있습니다.
useEffect(() => {
const countTime = () => {
console.log('100ms가 지났습니다.');
};
setInterval(countTime, 100);
}, []);
setInterval
함수를 100ms 마다 countTime
함수가 호출되도록 하고 있습니다.serInterval
을 통한 구독이 필요가 없어진 상황에서도 계속해서 콘솔이 출력되고 있을 것 입니다.useEffect(() => {
const button = document.getElementById('consoleButton');
const printConsole = () => {
console.log('button clicked');
};
button.addEventListener('click', printConsole);
// side effect를 clean up 하기 위한 함수를 선언한다.
const removeEventListener = () => {
button.removeEventListener('click', printConsole);
};
// clean up 함수를 return 한다.
return removeEventListener;
});
addEventListener
로 등록한 eventListner
는 removeEventListener
함수를 통해서 제거할 수 있기 떄문에 해당 동작을 하는 함수(clean up 함수)를 만든 뒤 콜백 함수 내에서 clean up 함수를 리턴해주었습니다.1. 다음 side effect를 발생시키기 전
2. 컴포넌트가 unmount 될 때