Lifecycle과 useEffect
Lifecycle과 useEffect 기본개념
컴포넌트는 Lifecycle이라는 개념이 있음
컴포넌트는
- 생성이 되고(mount)
- 재렌더링이 될수도 있고(update)
- 삭제가 될 수 있음(unmount)
이렇게 컴포넌트에 Lifecycle 개념을 이용하여 컴포넌트에 중간중간 간섭을 할 수 있음
주기(mount, update, unmount)에 코드를 달아주는 것으로 갈고리를 달아서 간섭할 수 있음
갈고리를 달음으로써 페이지 장착시, 업데이트시 , 제거시 코드를 실행할 수 있음
갈고리는 영어로 hook이라고 함
그래서 이러한 것을 Lifecycle hook이라고 부름
옛날에는 class 문법으로 컴포넌트를 만들었음
그 경우엔 안에 함수명(ex.componentDidMount)을 써주면 각각 특정 Lifecycle에서 코드를 실행할 수 있었음
요즘 React에서는 상단에서 useEffect import해오고
콜백함수 추가해서 안에 코드 적으면 이제 그 코드는 컴포넌트가 mount & update시 실행됨
이것이 Lifecycle hook
import {useState, useEffect} from 'react';
function Detail(){
useEffect(()=>{
//코드는 컴포넌트 로드 & 업데이트 마다 실행됨
console.log('안녕')
});
return (생략)
}
※ log가 2번 출력될 경우
index.js에 <React.StrictMode>라는 태그가 있으면 2번 출력됨
디버깅용으로 편하라고 2번 출력해주지만 싫다면 태그를 지우면 됨
▶ useEffect 바깥에 적어도 똑같이 컴포넌트 mount & update시 실행됨
컴포넌트가 mount & update시 function 안에 있는 코드도 다시 읽고 지나가기 때문
useEffect를 사용하는 이유는
useEffect 안에 적은 코드는 html 렌더링 이후에 동작하기 때문
만약 반복문을 100번 돌리는 코드가 있고 바깥쪽에 적어놓았다면 반복문을 돌리고 Html을 보여주는데
useEffect 안에 적으면 Html을 보여주고 나서 반복문을 돌림
이런 식으로 코드의 실행 시점을 조절할 수 있기 때문에 html 렌더링이 더 빠른 사이트를 원하면
쓸데없는 것들은 useEffect 안에 넣는것이 좋음
즉 컴포넌트의 핵심 기능은 Html 렌더링이니 외에 나머지 기능들은 useEffect안에 적는 것이 좋다는 것
오래걸리는 반복연산, 서버에서 데이터를 가져오는 작업, 타이머 등은 useEffect 안에 많이 적음
useEffect에 넣을 수 있는 실행조건
useEffect(()=>{ 실행할코드 }, [변수])
useEffect()의 둘째 파라미터로 [ ] 를 넣을 수 있는데 변수나 state같은 것들을 넣을 수 있음
[ ]에 있는 변수나 state 가 변할 때만 useEffect 안의 코드를 실행해줌
위에 예시는 변수가 변할 때만 useEffect 안의 코드가 실행됨
- [ ] 안에 state 여러개 넣을 수 있음
useEffect(()=>{ 실행할코드 }, [])
아무것도 안넣으면 컴포넌트 생성(mount)시 1회 실행하고 영영 실행해주지 않음
clean up function
useEffect 동작하기 전에 특정코드를 실행하고 싶으면 return ()=>{ } 안에 넣을 수 있음
useEffect(()=>{
그 다음 실행됨
return ()=>{
먼저 실행됨
}
}, [])
그럼 useEffect 안에 있는 코드를 실행하기 전에 return ()=>{ } 안에 있는 코드를 실행해줌
이것을 clean up function 이라고 부름
clean up function을 사용하는 이유
useEffect 안에 있는 코드를 실행할 때 싹 치우고 실행하는게 좋을 때가 있음
예로 setTimeout 타이머인데 setTimeout() 쓸 때마다 브라우저 안에 타이머가 하나 생김
근데 useEffect 안에 썼기 때문에 컴포넌트가 mount 될 때 마다 실행됨
타이머가 여러개 생길 수 있는 것!!
이런 버그를 방지하고 싶으면 useEffect에서 타이머 만들기 전에 기존 타이머를 싹 제거하라고 코드를 짜면 되는데
이럴때 clean up function을 사용하여 return ()=>{ } 안에 짜면 됨
useEffect(()=>{
let timer = setTimeout(()=>{ setAlert(false) }, 2000)
return ()=>{
clearTimeout(timer)
}
}, [])
- clean up function에는 타이머제거, socket 연결요청제거, ajax요청 중단 이런 코드를 많이 작성함
- 컴포넌트 unmount 시에도 clean up function 안에 있던것이 1회 실행됨
사용법 최종 정리
useEffect(()=>{ 실행할코드 })
재랜더링마다 코드 실행
useEffect(()=>{ 실행할코드 }, [])
컴포넌트 생성(mount)시 1회 실행
useEffect(()=>{
return ()=>{실행할코드}
})
useEffect 안의 코드 실행 전에 항상 실행
useEffect(()=>{
return ()=>{실행할코드}
}, [])
컴포넌트 삭제(unmount)시 1회 실행
useEffect(()=>{
실행할코드
}, [변수])
변수가 변경될 때만 실행