[React를 다루는 기술] 7장 - 컴포넌트 라이프사이클 메서드

3 minute read

😉 라이프사이클 메서드의 이해

  • 라이프 사이클 : 페이지에 렌더링되기 전인 준비 과정 ~ 페이지에서 사라질 때 까지
    • 처음으로 렌더링할때 어떤 작업을 처리해야할 때
    • 업데이트 하기 전, 후에 어떤 작업을 처리해야 할 때
    • 불필요한 업데이트를 방지할 때
  • Will 접두사 - 어떤 작업을 작동하기 전에 실행되는 메서드
  • Did 접두사 - 어떤 작업을 작동한 후에 실행되는 메서드

  • 라이프사이클은 총 세 가지 마운트, 업데이트, 언마운트 카테고리로 나뉜다.

    • 마운트 : 페이지에 컴포넌트가 나타남

    • 업데이트 : 컴포넌트 정보를 업데이트(리렌더링)

    • 언마운트 : 페이지에서 컴포넌트가 사라짐

🐱‍🐉 마운트

  • DOM이 생성되고 웹 브라우저상에 나타나는 것을 마운트(mount)라고 한다. 이 때 다음의 메서드를 호출한다.

  • 컴포넌트 만들기

    1. constructor 메서드 : 컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드
    2. getDerivedStateFromProps 메서드 : props 에 있는 값을 state 에 넣을 때사용하는 메서드
    3. render 메서드 : 준비한 UI를 렌더링하는 메서드
    4. componentDidMount 메서드 : 컴포넌트가 웹 브라우저상에 나타난 후에 호출하는메서드

🐱‍🐉 업데이트

  • 컴포넌트는 다음의 경우에 업데이트한다.
    • props 가 바뀔 때
    • state 가 바뀔 때
    • 부모 컴포넌트가 리렌더링될 때
    • this.forceUpdate 로 강제로 렌더링을 트리거할 때
  • 컴포넌트 업데이트
    1. getDerivedStateFromProps 메서드 : props 에 있는 값을 state 에 넣을 때사용하는 메서드 (마운트에서도 호출됨)
    2. shouldComponentUpdate 메서드 : 컴포넌트가 리렌더링을 해야 할지 말아야 할지를 결정하는 메서드 ( true 를 반환하면 리렌더링, false 면 리렌더링 하지 않음.)
    3. render 메서드 : 준비한 UI를 렌더링하는 메서드
    4. getSnapshotBeforeUpdate : 컴포넌트 변화를 DOM에 반영하기 직전에 호출하는 메서드
    5. componentDidUpdate : 컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드

🐱‍🐉 언마운트

  • 컴포넌트를 DOM에서 제거하는 것을 언마운트(unmount)라고 한다. 컴포넌트를 언마운트하면 다음의 메소드를 호출한다.
    • componentWIllUnmount : 컴포넌트가 웹 브라우저상에서 사라지기 전에 호출하는메서드
import React, { Component } from "react";

export default class LifeCycleSample extends Component {
  state = {
    number: 0,
    color: null
  };

  myRef = null;
  constructor(props) {
    super(props);
    console.log("constructor");
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    console.log("getDerivedStateFromProps");
    if (nextProps.color !== prevState.color) {
      return { color: nextProps.color };
    }
    return null;
  }

  componentDidMount() {
    console.log("componentDidMount");
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("shouldComponentUpdate", nextProps, nextState);
    return nextState.number % 2 !== 1;
  }

  componentWillUnmount() {
    console.log("componentWillUnmount");
  }

  handleClick = () => {
    this.setState({
      number: this.state.number + 1
    });
  };

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log("getSnapShotBeforeUpdate");
    if (prevProps.color !== this.props.color) {
      return this.myRef.style.color;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log("componentDidUpdate", prevProps, prevState);
    if (snapshot) {
      console.log("just before updating", snapshot);
    }
  }

  render() {
    console.log("render");
    const style = {
      color: this.props.color
    };
    return (
      <div>
        {/* {this.props.missing.value} */}
        <h1 style={style} ref={(ref) => (this.myRef = ref)}>
          {this.state.number}
        </h1>
        <p>color: {this.state.color}</p>
        <button onClick={this.handleClick}>plus</button>
      </div>
    );
  }
}

🤔 함수형 맛보기

// 함수형 컴포넌트로 작성 비교하니 함수형 hook이 더 명확하고 코드 양도 적다. https://adjh54.tistory.com/43
import React, { Component } from "react";

export default LifeCycleSample = () => {
    /**
   * 컴포넌트 호출 시 가장 먼저 호출이 되는 공간
   * 컴포넌트에서 사용 될 state나 함수들을 정의 하는 공간입니다.
   */
  console.log("가장 먼저 호충되는 구간 : constructor");
  
  const { number, setNumber } = useState(0);
  const { colur, setColor } = useState(null);
  let myRef = null;

  static getDerivedStateFromProps(nextProps, prevState) {
    console.log("getDerivedStateFromProps");
    if (nextProps.color !== prevState.color) {
      return { color: nextProps.color };
    }
    return null;
  }

 useEffect(() => {
        console.log("배열을 생략: 화면이 렌더링 된 이후 수행이 되며, 리 렌더링이 발생하는 경우 다시 수행이 된다(render)");
  });

 useEffect(() => {
        console.log("빈 배열: 화면이 마운트 될 때에만 수행됨: componentDidMount()과 동일");
  }, []); 
  // 가장 처음 렌더링 될 때 한번만 실행하고 싶을 때는 deps 위치에 빈 배열을 넣는다
    
  useEffect(() => {
      console.log("특정 props, state 값에 변화가 생겼을 경우 / number의 변화가 발생하였을 경우 수행이 된다. : componentDidUpdate()와 동일"
  }, [number]); 

  useEffect(() => {
  let timer = setTimeout(() => setShow(true), 3000); //unmount 시에도 memory에 timer가 남아 있지 않기 위해 cleanup 추가 (webSocket 도 마찬가지)
  return () => {
    clearTimeout(timer); // clean up (unmount 될 시에 시행)
  };
}, []);//unmout 될 때에만 실행되고 싶으면 빈 배열을 deps 에 추가해준다

  return ( 
    <>
      <div>
        {console.log("rendering...");}
        <h1 style={style} ref={(ref) => (myRef = ref)}>
          {number}
        </h1>
        <p>color: {color}</p>
        <button onClick={handleClick}>plus</button>
      </div>
    </>
  );
}

🐱‍🐉useEffect

💡 [ 메서드 구조 ] useEffect( function, deps? );

  • function : useEffect가 수행 될 때 실행되는 함수
  • deps [optional] : 배열 형태이며, 의존(dependency) 값을 의미한다.

💡 [ 더 알아가기 ] deps[optinal] 값의 의미

  1. 값이 없을 경우
    • useEffect(()⇒{})
    • 화면이 렌더링 된 이후 수행이 되며, 리 렌더링이 발생하는 경우 다시 수행이 된다
  2. 빈 배열 인경우
    • useEffect(()⇒{}, [])
    • 화면이 렌더링 된 이후에만 수행이 된다.
  3. 배열 값이 존재하는 경우
    • useEffect(()⇒{}, [값])
    • 화면이 렌더링 된 이후에 수행이 되고, ‘값’이 변경되었을 경우 해당 메서드가 수행이 된다.
  4. deps에 특정 값을 넣게 된다면 컴포넌트가 처음 마운트 될 때, 지정한 값이 바뀔 때, 언마운트 될 때, 값이 바뀌기 직전에 모두호출이 된다.

💡 clean-up 함수

  • Component의 unmount이전 / update직전에 어떠한 작업을 수행하고 싶다면 Clean-up함수를 반환해 주어야 한다.

    • unmount 될 때 : useEffect(func, [])
    • 특정값 update 직전 : useEffect(func, [특정값])
  • clean-up함수를 사용하게되면, 작동 순서는

    • re-render -> 이전 effect clean-up -> effect

Leave a comment