공부방

LifeCycle / useEffect 본문

React

LifeCycle / useEffect

코딩 화이팅 2024. 11. 25. 16:20

컴포넌트의 LifeCycle

  1. 생성(mount)
  2. 재렌더링(update)
  3. 삭제(unmount)

LifeCycle Hook

  • 컴포넌트 등장 전에 or 컴포넌트 사라지기 전에 or 컴포넌트 업데이트 되고 나서 등으로 코드를 실행할 수 있다.
  • 위의 그림처럼 갈고리를 달아서 코드를 넣어주면 된다.
  • 갈고리를 영어로 hook이라고 하기 때문에 LifeCycle Hook이라고 부름

옛날 React에서 LifeCycle hook 쓰는 법

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

요즘 React LifeCycle 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시 실행
    따라서 이게 LifeCycle hook
  • Detail 페이지 로드시 콘솔창에 '안녕' 출력
    • 콘솔창에 안녕이 2번 출력된다.
      =>index.js에 <React.StrictMode> 라는 태그가 있으면 2번 출력됨. 
      • 디버깅용으로 편하라고 2번 출력해주는데 싫다면 삭제해도 무방
  • 버튼을 누를 때마다 재렌더링되며 콘솔창에 안녕 출력

근데 useEffect 밖에 적어도 결과는 같다?

  • 컴포넌트가 mount, update시 function 안에 있는 코드도 다시 읽고 지나가기 때문에 useEffect 바깥에 적어도 똑같이 컴포넌트 mount, update시 실행된다.
  • useEffect 안에 적은 코드는 html 렌더링 이후에 동작하기 때문에 유용
function Detail(){

  (반복문 10억번 돌리는 코드)
  return (생략)
}


function Detail(){

  (반복문 10억번 돌리는 코드)
  return (생략)
}
  • 첫번째 코드처럼 대충 안에 적는다면 반복문을 돌리고 난 후 html을 보여준다.
  • 하지만 두번째 코드처럼 useEffect 안에 적는다면 html 보여주고 나서 반복문을 돌려준다.
  • 이런 식으로 코드의 실행 시점을 조절할 수 있기 때문에 조금이라도 html 렌더링이 빠른 사이트를 원하면 오래걸리는 반복 연산, 서버에서 데이터 가져오는 작업, 타이머 다는 것들은 useEffect 안에 넣는게 효율적

응용 - 동적인 ui 만들기

컴포넌트 안에 박스를 하나 만들고 이 페이지에 방문 후 2초 후에 박스가 사라지게 하기

※ 그 전에 알아야 할 JS 문법 setTimeout

setTimeout( ()=>{  1초 후 실행할 코드 }, 1000);
  • 1000이라고 숫자 적은 곳에 ms 단위로 시간을 적어주면 된다.(1000이면 1초)
function Detail(){

  let [alert, setAlert] = useState(true)
  useEffect(()=>{
    setTimeout(()=>{ setAlert(false) }, 2000)
  }, [])

  return (
  {
    alert == true
    ? <div className="alert alert-warning">
        2초이내 구매시 할인
      </div>
    : null
  }
  )
}
  1. 큰 순서로 따지면 UI 상태를 저장할 state 만들기
  2. state에 따라서 UI가 어떻게 보일지 작성
  • alert라는 state를 true로 바꾸면 노란박스가 보이고 false로 바꾸면 보이지 않는다.
  • 이제 페이지 접속 후 2초 후에 저걸 안 보이게 하려면 useEffect와 setTimeout을 사용하여 2초 후에 state 값을 false로 바꾸면서 안 보이게 할 수 있다.

useEffect 뒤에 ,[ ] 에 대해 알아보자

useEffect에 넣을 수 있는 실행 조건

useEffect(()=>{ 실행할코드 }, [count])
  • useEffect()의 둘 째 파라미터로 [ ]를 넣을 수 있다.
  • 여기에 변수나 state 같은 것들을 넣을 수 있다.
  • 그럼 [ ]에 있는 변수나 state가 변할 때만 useEffect 안의 코드를 실행해준다.
  • 따라서 위의 코드는 count라는 변수가 변할 때만 useEffect 안의 코드가 실행됨.
  • [ ] 안에는 여러 state를 넣을 수 있다.
useEffect(()=>{ 실행할코드 }, [])
  • 아무것도 넣지 않는다면 컴포넌트가 mount시 (로드시) 1회 실행하고 영영 실행되지 않는다.

clean up function

useEffect(()=>{ 
  그 다음 실행됨 
  return ()=>{
    여기있는게 먼저실행됨
  }
}, [count])
  • useEffect 동작하기 전에 특정코드를 실행하고 싶으면 return () => {} 안에 넣을 수 있다.
  • 그럼 useEffect 안에 있는 코드를 실행하기 전에 return () => {} 안에 있는 코드를 실행해준다.
  • 이것을 clean up function이라고 한다.
  • 이걸 쓰는 이유?
    • 위에 했던 타이머에서 활용을 해보면 setTimeout() 쓸 때마다 브라우저 안에 타이머가 하나 생긴다.
    • 근데 useEffect 안에 썼기 때문에 컴포넌트가 mount 될 때마다 실행이 된다.
    • 여차하면 타이머가 100개 1000개 생길수도 있음
    • 이러한 버그를 방지하기 위해 useEffect에서 타이머 만들기 전에 기존 타이머를 제거하라는 명령을 내리기 위해 사용될 수 있다.
useEffect(()=>{ 
  let a = setTimeout(()=>{ setAlert(false) }, 2000)
  return ()=>{
    clearTimeout(a)
  }
}, [])
  • 이것이 타이머를 제거할 때 사용되는 클린업 함수 (clearTimeout(타이머))
  • clean up function에는 타이머제거, socket 연결요청제거, ajax 요청 중단 이러한 코드를 많이 작성
  • 컴포넌트 unmount 시에도 clean up function 안에 있던게 1회 실행된다.

정리

useEffect(()=>{ 실행할코드 })
  • 재렌더링마다 코드를 실행가능
useEffect(()=>{ 실행할코드 }, [])
  • 컴포넌트 mount시 (로드시) 1회만 실행가능
useEffect(()=>{ 
  return ()=>{
    실행할코드
  }
})
  • useEffect 안의 코드 실행 전에 항상 실행
useEffect(()=>{ 
  return ()=>{
    실행할코드
  }
}, [])
  • 컴포넌트 unmount시 1회 실행
useEffect(()=>{ 
  실행할코드
}, [state1])
  • state1이 변경될 때만 실행

응용

input 하나 만들고 유저가 숫자 말고 다른 걸 입력하면 "숫자를 입력하세요"라는 안내메시지 출력

function Detail(){
  let [num, setNum] = useState('')

  useEffect(()=>{
    if (isNaN(num) == true){
      alert('그러지마세요')
    }
  }, [num])

  return (
    <input onChange={ (e) => { setNum(e.target.value) } } />
  )
}
  • <input>에 입력한 값은 출력해보면 전부 문자 형태로 출력된다.
  • 'isNaN()'을 사용하면 isNaN('abc') 이러면 true가 나오고 isNaN('123') 이러면 false가 나오는 걸 활용

'React' 카테고리의 다른 글

탭 UI  (0) 2024.11.28
ajax - axios  (0) 2024.11.26
styled-component  (0) 2024.11.25
URL 파라미터  (2) 2024.11.13
navigate, nested routes, outlet  (0) 2024.10.22