useEffect는 엄청 중요한 Hook이라고 한다. 리액트 컴포넌트가 렌더링(Mount, Update, Unmount)될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다.
useEffect 훅은 인자로 콜백함수를 받으며, 두 가지 형태를 기억하자
1. 첫번째 인자로 하나의 콜백함수만 받는 형태 - 랜더일 될때 마다 실행
useEffect(()=>{
//작업...
});
useEffect(()=>{
//작업...
},[value]);
만약 컴포넌틑가 언마운트되지 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 cleanup함수를 반환해주면 된다.
useEffect(()=>{ //구독... return()=>{ //구독 해지... } },[]);
코드로 알아보자
기본적으로 버튼을 누르면 count가 1씩 올라가는 코드를 만들었다.
import React, {useState, useEffect} from 'react';
function App(){
const [count, setCount] = useState(1);
const handleCountUpdate = () => {
setCount(count + 1);
};
useEffect(()=>{
console.log('렌더링')
});
return (
<div>
<button onClick={handleCountUpdate}>Update</button>
<span>count : {count}</span>
</div>
);
};
export default App;
Update버튼을 누르면 uesEffect가 계속 실행되고 있다. 정확하게는 컴포넌트가 렌더링 직후 uesEffect의 콜백이 실행이 되는 것이다.
import React, {useState, useEffect} from 'react';
function App(){
const [count, setCount] = useState(1);
const [name, setName] = useState('');
const handleCountUpdate = () => {
setCount(count + 1);
};
const handleInputChange = (e)=>{
setName(e.target.value)
}
//렌더링마다 실행
useEffect(()=>{
console.log('렌더링')
});
return (
<div>
<button onClick={handleCountUpdate}>Update</button>
<span>count : {count}</span>
<input type='text' value={name} onChange={handleInputChange}/>
<span>name : {name}</span>
</div>
);
};
export default App;
input을 하나 추가해주었다.
input에 입력을 할때마다 handleInputChange함수가 불리고 계속 렌더링이 일어나 useEffect도 계속 불리고있다.
useEffect가 매우 무거운 작업을 실행하고 있다면 비효율적이기 때문에 dependency array를 사용하여 count가 실행될 때만 적용해보자
import React, {useState, useEffect} from 'react';
function App(){
const [count, setCount] = useState(1);
const [name, setName] = useState('');
const handleCountUpdate = () => {
setCount(count + 1);
};
const handleInputChange = (e)=>{
setName(e.target.value)
}
//마운트 + count가 변경 시 실행
useEffect(()=>{
console.log('렌더링')
},[count]);
return (
<div>
<button onClick={handleCountUpdate}>Update</button>
<span>count : {count}</span>
<input type='text' value={name} onChange={handleInputChange}/>
<span>name : {name}</span>
</div>
);
};
export default App;
useEffect에 두번째 인자로 [count]를 넣어주면 끝! 또한, 위에서 언급했던 것처럼 배열을 비워주면 마운트 시에만 실행된다.
//App.js
import React, {useState, useEffect} from 'react';
import Timer from './component/Timer';
function App(){
const [showTimer, setShowTimer] = useState(false)
return (
<div>
{showTimer && <Timer/>}
<button onClick={()=>{setShowTimer(!showTimer)}}>Toggle Timer</button>
</div>
);
};
export default App;
Timer.js
import React,{useEffect} from 'react';
const Timer = (props) =>{
useEffect(()=>{
const timer = setInterval(()=>{
console.log('타이머 돌아가는중...')
},1000);
},[])
return(
<div>
<span>타이머를 시작핣니다. 콘솔을 보세요</span>
</div>
)
}
export default Timer
버튼을 누르면 Timer컴포넌트가 보이고 console에 타이머가 돌아간다. 하지만 다시 버튼을 누르면 Timer컴포넌트가 사라지지만 console에 타이머는 계속 돌아가고 있다.
타이머를 정리하려면 Timer 컴포넌트가 언마운트될 때 정리를 시킬 수 있도록, useEffect return값에 cleanup 함수를 넣어주면 된다!
import React,{useEffect} from 'react';
const Timer = (props) =>{
useEffect(()=>{
const timer = setInterval(()=>{
console.log('타이머 돌아가는중...')
},1000);
return ()=>{
clearInterval(timer);
console.log('타이머가 종료되었습니다.')
}
},[])
return(
<div>
<span>타이머를 시작핣니다. 콘솔을 보세요</span>
</div>
)
}
export default Timer
타이머가 종료되었다...!