[React] 13. 컴포넌트의 Lifecycle & useEffect

지렁·2023년 11월 6일
0

컴포넌트에게는 생명주기가 있다

컴포넌트는 !

  1. 생성이 될 수도 있고 (mount)
  2. 재렌더링이 될 수도 있고 (update)
  3. 삭제가 될 수도 있다. (unmount)

이 원리를 통해 컴포넌트가 장착될때, 업데이트될 때 특정 코드를 실행시킬 수 있다
(=컴포넌트 간섭)


Lifecycle을 이용한 useEffect 사용

🖤 Lifecycle hook이란?

컴포넌트 간섭을 위해 갈고리를 다는 것을 hook 이라고 한다

예전에는 class 문법으로 Lifecycle hook 을 사용하였지만

class Detail2 extends React.Component {
  componentDidMount(){
    //Detail2 컴포넌트가 로드되고나서 실행할 코드
  }
  componentDidUpdate(){
    //Detail2 컴포넌트가 업데이트 되고나서 실행할 코드
  }
  componentWillUnmount(){
    //Detail2 컴포넌트가 삭제되기전에 실행할 코드
  }
}

🖤 요즘에는 useEffect로 hook을 사용한다

import {useState, useEffect} from 'react';

function Detail(){

  useEffect(()=>{
    //여기적은 코드는 컴포넌트 로드 & 업데이트 마다 실행됨
    console.log('안녕')
  });

  let [count, setCount] = useState(0)
  
  return (
    <button onClick={()=>{ setCount(count+1) }}>버튼</button>
  )
}

상단에서 useEffect import해오고
콜백함수 추가해서 안에 코드 적으면 이제 그 코드는 컴포넌트가 mount & update시 실행된다

위 코드를 통해 Detail 페이지 로드시 콘솔창에 '안녕' 출력이 된다


🤔 안녕이 2번 출력되는 이유는?

index.js에 <React.StrictMode>라는 태그가 있으면 2번 출력해준다

디버깅용으로 편하라고 2번 출력해주는데 싫으면 저 태그를 제거하면 된다

🤔 useEffect 밖에 적어도 똑같은 이유는?

useEffect 안에 적은 코드는 html 렌더링 이후에 동작한다

굉장히 시간이 오래걸리는 코드같은 경우는 useEffect가 뭔가 유용하게 사용될 것이다!
이 원리를 이용하여 useEffect를 사용하면 된다

🖤 useEffect를 사용하여 2초 뒤 사라지는 알람창 띄우기

Detail 페이지에서 "2초 이내 구매 시 할인" 알람창을 2초간 띄워보겠다

Detail.js

우선 UI를 만들어주고
useEffect에서 setTimeout 함수를 사용하였다

그리고 setTimeout 함수 내에서 2초 뒤 display:none 속성을 추가하는 방식으로 구현하였다

export function Detail({data}){
  useEffect(()=>{
    setTimeout(()=>{
      document.querySelector('.alert').style.display='none'
    },2000)
  })
    return(
      <>
        <div className="alert alert-warning">2초 이내 구매시 할인</div>
        ...

상세페이지 접속하자마자 알람창이 뜨고 2초 후 사라지며 정상작동이 된다!

💥 하지만 이렇게 하면 안된다 ?

내가 구현한 방식은 DOM 요소를 직접 조작하는 방식이다
하지만 이런 방식은 React의 선언적 패러다임에 위배된다.

React는 UI의 상태(state)를 자바스크립트로 선언하고, 그 상태에 따라 UI가 어떻게 보일지를 정의하는 것을 권장한다
➡ React에서 상태를 사용하여 컴포넌트를 보여주거나 숨기는 방식으로 구현해야한다

[정리] 리액트에서 동적인 UI 만드는 법

  1. UI 상태를 저장할 state 만들고
  2. state에 따라서 UI가 어떻게 보일지 작성

우선 show state를 만들어서 2초 뒤의 show 상태를 다르게 만들었다
그리고 &연산자를 이용하여 show=true 일때 알람창의 UI를 보여주었다 !

export function Detail({data}){
  let [show,setShow]=useState(true)

  useEffect(()=>{
    setTimeout(()=>{
     setShow(false)
    },2000)
  })
    return(
      <>
        {show && <div className="alert alert-warning">2초 이내 구매시 할인</div>}
     
        ...

🖤 useEffect 실행조건

위의 useEffect는 mount, update 될 때마다 안의 코드가 실행된다
약간 비효율 적일 수 있기 때문에 mount 될 때만 알람창을 띄우는 것이 좋다

🤔 mount 시에만 작동하고 싶다면 ?

useEffect()의 둘째 파라미터로 [ ] 를 넣을 수 있는데 이곳에 변수나 state같은 것들을 넣을 수 있다
➡ [ ]에 있는 변수나 state 가 변할 때만 useEffect 안의 코드를 실행해준다

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

반면, 아무것도 넣지 않으면 mount 시(로드 시) 1회 실행하고 영영 실행해주지 않는다

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

🤔 useEffect 동작 전 특정 코드를 실행하고 싶다면?

clean up function 사용

useEffect 내의 return 문이다
useEffect 실행전 & 컴포넌트 unmount 시 실행

useEffect(()=>{ 
  그 다음 실행됨 
  return ()=>{
    여기있는게 먼저실행됨
  }
}, [count])

그럼 useEffect 안에 있는 코드를 실행하기 전에 return ()=>{ } 안에 있는 코드를 실행해줍니다

clean up function 사용하는 이유

타이머, 서버 요청 등은 여러 번 실행하면 버그가 생길 수 있기 때문에 한번 동작하면 다시 동작 전 청소해주고 다시 동작시켜야 한다
ex ) 타이머제거, socket 연결요청제거, ajax요청



🖤 정리

mount, update 마다 실행

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

mount 시 1회 실행

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

useEffect 실행 전 항상 실행

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

컴포넌트 unmount 시 1회 실행

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

state, 변수 변경할 때마다 실행

useEffect(()=>{ 
  실행할코드
}, [state1])
profile
공부 기록 공간 🎈💻

0개의 댓글