React : Lifecycle & useEffect
1. useEffect 란?
React 컴포넌트에게는 생명주기가 있다.
1. 생성이 될 수도 있고 (Mount)
2. 재렌더링이 될 수도 있고 (Update)
3. 삭제가 될 수도 있다. (Unmount)
리액트에서는 이 타이밍에 맞춰 특정한 이벤트들을 발생시킬 수 있다.
"이 컴포넌트 등장 전에 이것좀 해줘"
"이 컴포넌트 사라지기 전에 이것좀 해줘"
"이 컴포넌트 업데이트 되고 나서 이것 좀 해줘"
갈고리를 달아서 코드를 넣어주면 된다. -> Lifecycle hook
import {useEffect} from 'react';
function Detail(){
useEffect(()=>{
//여기적은 코드는 컴포넌트 로드 & 업데이트 마다 실행됨
console.log('안녕')
});
return (생략)
위의 코드는, 컴포넌트가 마운트 되었을때, 그리고 재렌더링 될 때 마다 console.log('안녕')이 실행된다.
하지만
사실 useEffect 밖에서 함수를 실행해도 마찬가지로 컴포넌트 mount & update시 실행된다.
useEffect 안에 적는 것과 밖에 적는 것의 가장 큰 차이는,
useEffect 안에 적은 코드는 html 렌더링 이후에 동작한다는 것.
만약에 로딩하는데 시간이 아주 오래걸리는 함수가 있을 때 html 렌더링 전에 실행되게 되면, Html 화면이 나오지 않은 채로 오랜 시간 방치되게 된다.
이런 경우에 useEffect 안에 해당 코드들을 넣으면 렌더링이 완료된 이후에 실행하게 하여 원활하게 만들 수 있다. 사람들에게 빠른 느낌을 줄 수 있다.
--
함수의 핵심기능 외의 부가적인 기능들을 프로그래밍 용어로 side effect라고 부른다.
사실 useEffect도 side effect에서 파생된 단어이다.
컴포넌트의 핵심 기능은 html 렌더링이다. useEffect는 그 외의 부가적인 기능들은 담기 위한 용도가 있다.
렌더링 외의 여러 이벤트(scroll..) 와 아래 작업들에 주로 이용된다.
- 오래걸리는 반복연산
- 서버에서 데이터 가져오는 작업(서버에서 데이터 받아올 때 처음에 한번만 받아오면 되니까 유즈이펙트 쓰면 좋다.)
- 타이머 (setTimeInterval, setTimeout)
사용법)
useEffect(()=>{ 실행할코드 })
1. 이렇게 쓰면 재렌더링마다 코드 실행가능.
useEffect(()=>{ 실행할코드 }, [])
2. 컴포넌트 mount시 (로드시) 1회만 실행가능.
useEffect(()=>{
return ()=>{
실행할코드
}
})
3. return에 넣어두면 useEffect 안의 코드가 실행되기 전에 실행된다. Unmount 될 때마다 실행된다.
ex) clearInterval 의 경우 넣어둘 수 있다. setInterval 실행전에 기존의 인터벌 정리하고 실행할 때.
ex) 데이터 요청을 하고, 기다리는 사이에 재렌더링이 되면 다시 useEffect가 실행되어서 무한루프에 걸린다.
그때 return에, 기존 요청은 제거해주세요. 요청을 써두면 된다.
useEffect(()=>{
return ()=>{
실행할코드
}
}, [])
4. 컴포넌트가 unmount 될 때 1회만 실행됩니다.
useEffect(()=>{
실행할코드
}, [state1])
5. 이러면 state1이 변경될 때만 실행된다.
2. 클래스 컴포넌트 & 함수 컴포넌트
class Detail2 extends React.Component {
componentDidMount(){
//Detail2 컴포넌트가 로드되고나서 실행할 코드
}
componentDidUpdate(){
//Detail2 컴포넌트가 업데이트 되고나서 실행할 코드
}
componentWillUnmount(){
//Detail2 컴포넌트가 삭제되기전에 실행할 코드
}
}
클래스 컴포넌트에서는 라이프사이클이 컴포넌트 중심으로 돌아간다. 컴포넌트가 마운트 되고 나서(componentDidMount), 업데이트 되었을 때(componentDidUpdate), 언마운트(componentWillUnmount) 될 때 이벤트가 실행 된다.
함수 컴포넌트에서는 특정한 데이터에 대해서 라이프사이클이 진행된다.
hidden이라는 state가 바뀌는 것에 따라서 라이프사이클을 정하고 싶다면 아래와 같이 대괄호 안에 state를 넣어주면 된다.
useEffect(() => {
console.log('hidden changed');
}, [hidden]);
데이터가 여러 개라면 useEffect는 데이터의 개수에 따라 여러 번 사용하면 된다.
useEffect(() => {
console.log('hidden changed');
}, [hidden]);
useEffect(() => {
console.log('shown changed');
}, [shown]);
3. Cleanup Effect
이전에 일으킨 Side Effect를 정리할 필요가 있을 때 사용합니다.
useEffect(() => {
function handleScroll() {
console.log(window.scrollY)
}
document.addEventListener("scroll", handleScroll)
}, [])
위의 코드는 페이지에 스크롤 이벤트가 일어날 때마다 console에 현재 스크롤이 위치한 Y 좌표를 출력한다.
Side Effect이므로 useEffect 안에서 사용하고, 이벤트 리스너는 한번만 등록하면 되기 때문에 의존성 배열에는 빈 배열을 넣어주었다.
우리가 이 페이지를 벗어났을 때 이 이벤트 리스너는 더 이상 필요없어 진다면 Effect를 정리해줘야 한다.
이 때마다 Cleanup Effect를 일으킬 수 있도록 useEffect 안에 해당 로직을 정리하는 동작을 정의해두면 된다.
function handleScroll() {
console.log(window.scrollY)
}
document.addEventListener("scroll", handleScroll)
return () => {
document.removeEventLisnter("scroll", handleScroll)
}
}, [])
주의할 점은 단순히 컴포넌트가 생성되고, 사라지는 시점에만 Cleanup Effect가 실행되는 건 아니라는 것.
다음 Effect가 일어나기 전에, 이전 Effect의 영향을 정리해줘야 한다.
이것을 활용해 setTimeout한 것을 useEffect return을 통해서 clearTimeout할 수 있다.
https://www.zerocho.com/category/React/post/5f9a6ef507be1d0004347305