Lifecycle과 useEffect

코쓱타드·2023년 6월 5일
0
post-thumbnail

1. 컴포넌트의 Lifecycle

- 생성이 될 수도 있고 (전문용어로 mount)
    컴포넌트가 브라우저에 보여지면 mount 된다고 한다

- 재렌더링이 될 수도 있고 (전문용어로 update)
    컴포넌트 안에서 state 같은걸 조작했을 때

- 삭제가 될 수도 있다. (전문용어로 unmount)

<이거를 왜 배울까?>

lifecycle을 알고 있으면 과정 중간중간에 간섭(코드실행) 할 수 있다.
컴포넌트가 장착될때 특정 코드를 실행할 수도 있고,
컴포넌트가 업데이트될 때 특정 코드를 실행할 수도 있다.
그러면 재밌는 기능을 개발할 수 있다.

<요즘 React에서 Lifecycle hook 쓰는법>

import {useEffect} from 'react';
// 상단에서 useEffect import 해오고

function Detail(){
// useEffect()안에 콜백함수 추가.
  useEffect(()=>{
    //여기적은 코드는 컴포넌트 로드 & 업데이트 마다 실행됨
    console.log('안녕')
		// 안녕이 2번 출력되는데 리액트 환경에선 원래 그럼.
		// 디버깅용으로 편하라고 2번 출력해주는거임.
		// 이게 싫다면 index.html로 가서 <React.StrictMode> 없애면 된다. 
  });
  
  return (생략)
}

<useEffect 쓰는 이유>

  • useEffect의 동작원리
function Detail(props){
	console.log('안녕')	// 바깥에서도 안에 적은 것과 같이 실행이 되는데?...
  useEffect(()=>{
    
  });

function Detail(props){

  useEffect(()=>{
    console.log('안녕')	
 // useEffect 안에 적은 코드는 렌더링이 다 되고나서 실행이 된다.(즉 가장 마지막에 실행된다.)

  });
function Detail(props){

  useEffect(()=>{
    
  });
// 복잡한 연산을 해줘야 한다고 가정해보자
for(let i = 0; i < 10000; i++){
		console.log(1);
	}
}

위의 코드는 어떤식으로 동작하냐면 Detail 컴포넌트가 필요해졌을 때 JS는 위에서 부터 코드를 차례로 읽기 때문에 for 반복문 부터 읽게된다.

그런데 for 반복문 실행하는데 엄청 오래걸리기 때문에 비효율적인데 이 오래걸리는 작업을 useEffect에 넣게되면 가장 마지막에 읽기 때문에 효율적이다.

(정확한 실행 시점은 return( )안에 있는 html 코드들이 랜더링 된 후에 실행 된다)

<useEffect를 어디에 써?>

어려운 연산(시간이 오래걸리는 작업)
서버에서 데이터 가져오는 작업
타이머가 필요할때

📑 컴포넌트의 핵심 기능은 html랜더링이라 그거 외의 기능들은 useEffect 안에 적으면 된다.

<useEffect에 넣을 수 있는 실행조건>

useEffect에 둘째 파라미터로 [ ]을 넣을 수 있는데 그곳에 변수나 state같은 것들을 넣을 수 있다.

그렇게 하면 [ ]에 있는 변수나 state가 변할 때만 useEffect 안의 코드를 실행해준다.

(참고. [ ] 안에 state 여러 개 넣을 수 있다)

아래와 같이 아무것도 넣지 않으면 컴포넌트 mount시(로드시) 1회 실행하고 영영 실행해주지 않는다.

let [count, setCount] = useState(0);
useEffect(() => { 실행할코드 }, [count])
// mount될때랑 count라는 state가 update될 때마다 실행된다. 
useEffect(() => { 실행할코드 }, [])
// 디펜던시가 비어있으면 mount시에만 실행되고 update시에는 실행되지 않는다.

useEffect 동작하기 전에 특정코드를 실행하고 싶으면 아래와 같이 작성하면 된다.

이런걸 clean up function이라 한다.

useEffect(()=>{
	  // (2) .. 그 다음 실행됨
	return ()=>{
		// (1) .. 먼저 실행됨
	}
}, []);

<왜 이런 기능이 있을까?>

useEffect 안에 있는 코드를 실행할 때 치우고 깔끔한 상태로 실행하기 위해 존재한다.

  • 예시) setTimeout( ) 쓸 때마다 브라우저 안에 타이머가 하나씩 생긴다. 근데 useEffect 안에 썼기 때문에 컴포넌트가 mount 될 때마다 실행된다. 우리가 코드를 잘못짜서 타이머가 100개, 1000개가 될 수도 있다. 이러한 버그를 방지하려면 useEffect에서 타이머를 만들기 전에 기존 타이머를 전부 제거하라고 코드를 짜야하는데 그런 코드를 ‘return ( )⇒{ }’안에 짜면 된다.
    useEffect(()=>{
    	let a = setTimeout(()=>{~~~~~},2000)
    	return ()=>{
    		clearTimeout(a)
    	}
    
    }, [])
    • 타이머를 제거하고 싶으면 clearTimeout(타이머)와 같이 코드 짜면 된다.
useEffect(()=>{
// 서버로 데이터 요청하는 코드(2~3초 소요)
	return ()=>{
		// 기존 데이터 요청은 제거해주세요.
}, [])

데이터 요청하는데 2~3초가 걸린다면 그 사이에 재렌더링이 될 수도 있고 그렇게되면 계속해서 요청하는 코드가 실행이 될 것이고 버그도 발생할 것이다.

이럴 때도 cleanup 함수를 사용한다.

♨️결론

1. 재렌더링마다 코드 실행가능.

useEffect(()=>{ 실행할코드 })

2. 컴포넌트 mount시 1회만 실행가능.

useEffect(()=>{ 실행할코드 }, [])

3. useEffect 안의 코드 실행 전에 항상 실행됨.

useEffect(()=>{ 
  return ()=>{
    실행할코드
  }
})

4. 컴포넌트 unmount시 1회 실행됨.

useEffect(()=>{ 
  return ()=>{
    실행할코드
  }
}, [])

5. state1이 변경될 때만 실행됨.

useEffect(()=>{ 
실행할코드
}, [state1])

출처. 코딩애플

profile
개발자의 길 from 2022.12

0개의 댓글