컴포넌트에는 Lifecycle이라는 개념이 있다.
컴포넌트는 생성(mount)되고 리랜더링(update)되며 삭제(unmount)된다.
우리는 이러한 순간들 마다 함수를 호출하거나 무언가를 실행할 수 있다.
"Detail 컴포넌트 등장 전에 이것좀 해줘"
"Detail 컴포넌트 사라지기 전에 이것좀 해줘"
"Detail 컴포넌트 업데이트 되고나서 이것좀 해줘"
이렇게 코드좀 실행해달라고 간섭할 수 있는데 간섭은 갈고리를 달아서 한다.
갈고리를 달고, 코드를 넣어주면 된다. 이 갈고리를 'Lifecycle hook' 이라고 부른다.
import {useState, useEffect} from 'react';
function Detail(){
useEffect(()=>{
//여기적은 코드는 컴포넌트 로드 & 업데이트 마다 실행됨
console.log('안녕')
});
return (생략)
}
상단에서 useEffect import 하고, 컴포넌트 내에서 콜백함수 추가해서 안에 코드 적으면 이제 그 코드는 컴포넌트가 mount & update시 실행된다. 위 코드는 Detail 컴포넌트가 생성되거나 업리랜더링 될 때 마다 콘솔에 '안녕'이 출력될것이다.
물론 useEffect() 밖에 console.log를 적어도 컴포넌트가 mount & update 될 때마다 '안녕'이 출력된다. 이 둘의 차이는 useEffect안의 코드는 html이 모두 랜더링 된 후에 실행된다는 것이다. 즉 조금이라도 html 랜더링이 빠른 사이트를 원한다면 우선순위가 낮은 것들은 useEffect 안에 넣는것이 효과적이다.
useEffect(()=>{ 실행할코드 }, [count])
이렇게 대괄호를 콜백함수 뒤에 넣어주면 count라는 변수가 변할 때만 useEffect 안의 코드를 실행해달라는 뜻이다. 만약 대괄호를 비운채로 넣는다면 컴포넌트 mount시 1회 실행하고 그 뒤로는 실행하지 않는다.
useEffect(()=>{
그 다음 실행됨
return ()=>{
여기있는게 먼저실행됨
}
}, [count])
useEffect 동작 전에 특정코드를 실행하고 싶으면 return ()=>{} 안에 넣을 수 있다. 그럼 useEffect 안에 있는 코드를 실행하기 전에 return ()=>{} 안에 있는 코드를 먼저 실행한다. 그리고 이걸 'clean up function'이라고 부른다. 예를들어 setTimeout 코드를 useEffect 안에서 쓰면 useEffect가 실행될 때 마다 타이머가 하나씩 생기는데 이가 반복되면 무수한 타이머가 생겨 버그를 야기한다. 이를 방지하려면 return ()=>{} 안에 타이머를 제거하는 clearTimer(타이머)를 작성하면 된다.
그래서 clean up function에는 타이머제거, socket 연결요청제거, ajax요청 중단 이런 코드를 많이 작성한다.
정리
1. 재랜더링마다 코드 실행
useEffect(()=>{ 실행할코드 })
2. mount시 1회만 실행
useEffect(()=>{ 실행할코드 }, [])
3. useEffect 코드 실행 전에 실행
useEffect(()=>{
return ()=>{
실행할코드
}
})
4. 컴포넌트 unmount시 1회 실행
useEffect(()=>{
return ()=>{
실행할코드
}
}, [])
5. state1이 변경될 때만 실행
useEffect(()=>{
실행할코드
}, [state1])