TIL | 리액트 LifeCycle과 useEffect

0l0l·2021년 11월 2일
0

TIL

목록 보기
85/86

클래스 컴포넌트에서 리액트 라이프사이클을 이용하는 방법!

렌더링되어 컴포넌트가 DOM에 붙는 순간에 특정 동작을 하게 만들 수 있다.
(index.js에서 root에 접근하여 ReactDOM.render()하는) render() 함수가 실행되어 리액트가 jsx를 DOM에 붙여주는 딱 그 순간!😝에 실행될 동작을 구현한다.

componentDidMount()

처음 실행되는 render()가 성공적으로 실행(컴포넌트가 첫❗ 렌더링)된 후 componentDidMount()가 실행된다.
즉, 컴포넌트가 화면에 보이자마자 실행될 동작을 작성한다.
그러나 setState로 리렌더링되고나서는 componentDidMount()는 실행되지 않는다.

📍주의! render() 안에서 setState를 사용하면 무한 렌더링되기 때문에 문제가 발생되므로 setState를 쓰고 싶을 때는 componentDidMount() 안에서 사용한다.

componentWillUnmount()

componentDidMount()에서 했던 작업을 제거하는 용도로, 컴포넌트가 제거되기 직전componentWillUnmount()가 실행된다.
자식 컴포넌트 입장에서 부모 컴포넌트가 자신을 제거할 때 실행된다.
componentDidMount()와 componentWillUnmount()는 짝꿍!💑

componentDidUpdate()

componentDidMount()가 첫번째 렌더링에서만 실행된다면, componentDidUpdate()는 setState가 실행되거나 props가 변경되는 경우처럼 '리렌더링'된 후에 실행된다.

✨ Class Component일 때의 LifeCycle(라이프사이클) 과정

constructor → render → (ref) → componentDidMount
(경우 1) setState 또는 props 바뀔 때 → shouldComponentUpdate(true 리턴) → componentDidUpdate
(경우 2) 부모가 나(자식 컴포넌트)를 제거할 때 → componentWillUnmout → (자식 컴포넌트) 소멸


  • 보통 componentDidMount()비동기 요청(ex. setInterval, setTimeout) 을 하고, componentWillUnmount()에서 비동기 요청을 취소(ex. clearInterval, clearTimeout) 한다.
    해당 컴포넌트가 사라졌다해도 비동기 요청을 제거하지 않으면 계속 실행된다.
    컴포넌트가 삭제되었다가 추가될 때마다 그만큼 비동기 요청이 추가되어 실행되는 비동기 요청이 많아지는 문제가 발생된다.
    그리고 계속해서 메모리를 차지하므로 메모리 누수가 발생된다.
    그러므로 완료되지 않은 비동기 요청은 componentWillUnmount()에서 반드시 정리한다.(필수!)

  • (참고. 자바스크립트 관련 클로저 문제)
    비동기 함수가 밖에 선언한 변수를 참조하면 클로저 문제가 발생한다. 함수 안에서 참조할 수 있도록 하기!

  • 리액트에서 많이 쓰이는 패턴!
    메서드 안에 함수를 호출하는 경우 아래와 같이 두가지 방법으로 사용할 수 있다. (빈 화살표 위치 주의!)
    실무에서는 함수를 연달아서 쓰는 고차함수(HOF) 패턴의 방식을 많이 볼 수 있다.
onClickBtn = (choice) => {
  ... 
}
<button onClick={() => this.onClickBtn('가위')}가위</button>

// 또는 간단하게 만들고 싶다면 고차함수로 작성
onClickBtn = (choice) => () => {
  ... 
}
<button onClick={this.onClickBtn('가위')}가위</button>
  • class 안에 모두 작성하여 많은 것을 묶어두려 하지말고, state로 사용되지 않는 변수(상수 형태의 객체)는 class 밖으로 빼서 선언하는 것이 좋다.

함수형 컴포넌트의 useEffect

useEffect(() => { // componentDidMount, componenetDidUpdate 역할
  return () => { // componentWillUnmount 역할
    ...
  }
}, []);
  • 함수형 컴포넌트의 경우, 라이프사이클을 사용하지 않지만 useEffect Hook를 사용하여 'componentDidMount'와 'componentDidUpdate'의 역할을 대체할 수 있다. (완전하게 1대1 대응하는 것은 아님)

  • useEffect() 안에 함수의 return문이 'componentWillUnmount' 역할을 대신한다.
    즉, useEffect가 주요 라이프사이클 3가지를 한번에 처리하는 것이다.

  • useEffect도 useState와 useRef와 마찬가지로 함수 컴포넌트 안에 작성한다.

  • useEffect의 인자

    • 첫번째 인자: 함수
    • 두번째 인자: 배열
      useEffect를 다시 실행하고 싶은 state를 값으로 넣고, JS의 클로저 문제를 해결할 수 있다.
      • 배열 안에 넣은 값이 바뀔 때 useEffect가 실행된다.(componentDidUpdate 역할)
      • 빈 배열이라면 처음에만 한 번 실행된다.(componentDidMount 역할)

클래스 컴포넌트의 LifeCycle vs. 함수형 컴포넌트의 Hooks

구분클래스 컴포넌트의 LifeCycle함수형 컴포넌트의 Hooks
문법componentDidMount
componentWillUnmount
componentDidUpdate
useEffect
렌더링 시componentDidMount, componentDidUpdate 실행전체 실행
state 관리라이프사이클 각각 전체 state를 관리한개 또는 여러개의 state 관리
(effect가 상이한 각각의 useEffect 작성)
// start, end, result 로 state 설정한 경우,
componentDidMount() { // start, end, result 통째로!
  this.setState({
    start: '시작',
    end: '끝',
    result: '결과',
  })
}

useEffect(() => { // start 또는 end 또는 result
  setStart();
  setEnd();
}, [start, end]);
useEffect(() => { // start 또는 end 또는 result
  setResult();
}, [result]);

📌 라이프사이클과 비교하여 useEffect 패턴 암기하기!

  • 함수 컴포넌트는 매번 다시 실행되는 특성이 있다.
    클래스 컴포넌트의 라이프사이클에서는 componentWillUnmount가 실행되지 않지만, 함수형 컴포넌트의 useEffect에서는 두번째 인자인 배열 안에 값이 바뀔 때마다 전체가 실행된다.
    (setInterval 실행/종료를 반복하여 마치 setTimeout과 같은 효과)
  • state마다 다른 effect를 낼 수 있기 때문에 useEffect를 여러번 쓸 수 있다.
    클래스 컴포넌트의 경우 componentDidMount나 componentDidUpdate에서 모든 state를 조건문으로 분기 처리한다.
  • 부모 컴포넌트에서 Hook을 사용하면 부모 컴포넌트 렌더링될 때마다 자식 컴포넌트에도 영향을 미친다.
    리렌더링을 막기 위해서는 memo로 부모 함수 컴포넌트를 감싸준다.

*출처: Youtube ZeroCho TV 리액트 기본 강좌

profile
천방지축 빙글빙글

0개의 댓글