Frontend Study - 2/React

React : Lifecycle & useEffect

갓데미 2022. 7. 12. 21:51

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://codingapple.com/

https://www.zerocho.com/category/React/post/5f9a6ef507be1d0004347305