1. useEffect란?
useEfftect는 컴포넌트가 렌더링 된 후에 특정 작업을 수행 할 수 있도록 하는 hook 입니다. 여기서 말하는 특정 작업을 side effect라고 하는데 이러한 side effect에는 단순한 변수 설정 뿐만 아니라 api 호출과 같은 비동기적인 처리를 포함합니다. 이러한 기능은 컴포넌트의 생명주기에 관한 메서드를 함수형 컴포넌트에서 사용 할 수 있게 해줍니다. 컴포넌트 생명주기에는 기본적으로 3단계가 존재합니다.
- ComponentDidMount : 컴포넌트가 생성 될 때, 렌더링 완료 시 실행
- ComponentDidUpdate : 컴포넌트의 생성이 완료 된 후 update 되었을 때 실행
- ComponentWillUnmount : 컴포넌트가 제거되기 직전에 실행
2. useEffect 사용법
useEffect는 side effect에서 실행 될 콜백 함수와 update에서 사용될 의존성 배열을 인자로 받습니다. 의존성 없이 렌더링 될 때마다 실행 되게 할땐 의존성 배열을 생략 해주시면 되고, 만약 의존성 배열을 빈 배열로 입력 하면 첫 렌더링 시에만 실행 됩니다.
3. 예제코드
index.js
import styles from '@/styles/Home.module.css'
import React, { useEffect, useRef, useState } from 'react'
import HorizontalScroll from '../components/HorizontalScroll/HorizontalScroll'
export default function Home() {
const [input, setInput] = useState(0)
const [list, setList] = useState([]);
const onInputChange= (e)=>{
setInput(e.target.value)
}
useEffect(()=>{
console.log("[DidMount] 최초 렌더링")
setInput(2)
},[])
return (
<main >
<div>
몇개를 생성할까요?
</div>
<input onChange={onInputChange} defaultValue={input}/>
{/* <button onClick={()=>pushArr()}>생성하기</button> */}
<div>
<p>==================================</p>
{
input == 0 ? (null):(
<HorizontalScroll length={input}>
</HorizontalScroll>
)
}
</div>
</main>
)
}
HorizontalScroll.js
import styles from './HorizontalScroll.module.css'
import React, { useEffect, useRef, useState, useMemo } from 'react'
export default function HorizontalScroll({ length}) {
const [arrList, setArrList] = useState([])
useEffect(()=>{
createList(length)
return () => {
console.log(`[WillMount] 이전 리스트 길이 : ${length}`);
};
},[length])
useEffect(()=>{
return () => {
console.log("[WillUnmount] 마지막 클린업");
};
},[])
useEffect(()=>{
console.log("[DidMount] 리스트 랜더링");
})
const createList = (number) =>{
let result = []
for(let i = 0; i < number; i++) result.push(`${i+1}번`)
console.log(`[DidUpdate] 생성된 리스트 길이 : ${number}`)
setArrList(result)
}
return (
<main >
<div className={styles.list>
{
arrList.map((item, index) => (
<div className={styles.item} key={index}
onClick={() => {
console.log(`${index}번 클릭입니다 created by ${input}`)
}}>
<p>{item}</p>
</div>
))
}
</div>
</main>
)
}
4. DidMount - 렌더링 되었을 때 실행하기
예제코드 HorizontalScroll.js 에서 아래의 부분이 해당됩니다. 컴포넌트가 렌더링 될 때마다 로그가 출력됩니다.
useEffect(()=>{
console.log("[DidMount] 리스트 랜더링");
})
만약 가장 처음 렌더링 시에만 실행하고 싶으면 index.js의 아래 코드 처럼 의존성 배열에 빈배열을 입력하면 됩니다. 예제에서는 최초 렌더린 시에는 입력값을 2로 설정하도록 하고 있습니다.
useEffect(()=>{
console.log("[DidMount] 최초 렌더링")
setInput(2)
},[])
5. DidUpdate 컴포넌트 렌더링 완료 후 특정 state의 변경이 있을 때
HorizontalScroll.js 에서 아래의 부분이 해당됩니다. 해당 부분은 props로 받은 length의 값이 변할때마다 리스트를 다시 생성하 주고 있습니다.
useEffect(()=>{
createList(length)
return () => {
console.log(`[WillMount] 이전 리스트 길이 : ${length}`);
};
},[length])
6. WillUnmount 컴포넌트가 삭제될 때
HorizontalScroll.js 의 아래 코드는 length의 값이 변경되면서 컴포넌트가 리렌더링 되게 되는데 리렌더링되면서 컴포넌트가 삭제되고 다시 생성되게 되는데 이 과정에서 삭제 되기전에 clean up 함수를 통해 이전 length값을 출력 해주게 됩니다. 또한 Didmount때와 마찬가지로 빈 의존성 배열에 빈 배열을 넣어 줄 경우 완전히 사라질 때만 실행 됩니다. 예제 에서는 길이를 0으로 입력했을 때 컴포넌트가 사라지므로 이 경우에만 크실행 됩니다.
useEffect(()=>{
createList(length)
return () => { //리렌더링 될 때 마다 클린업함수 실행
console.log(`[WillMount] 이전 리스트 길이 : ${length}`);
};
},[length])
useEffect(()=>{
return () => { //완전히 사라질 때만 클린업 함수 실행
console.log("[WillUnmount] 마지막 클린업");
};
},[])
7. 결과 화면
이상으로 useEffect의 활용방법과 component의 liftcycle에 대해서 알아보았습니다. useEffect만 잘 활용 하여도 필요없는 component의 호출을 줄일 수 있어서 앱 성능 향상에 큰 도움이 될 수 있습니다.
잘못된 부분에 대한 지적은 언제든지 환영합니다.