[React] LifeCycle API

HongDuHyeon·2022년 3월 13일
0
post-thumbnail
해외 직구로 시킨 모자가 3주만에 왔다.

1. LifeCycle API

2. 컴포넌트 초기 생성

2-1. constructor

constructor는 먼저 props를 파라미터로 받아오고 안에 super(props)를 해줘야하는데 용도는 원래 갖고 있던 생성장 함수를 불러와주고 하고 싶은 작업을 할때 사용된다.

constructor(props) {
  super(props);
  console.log('constructor');
}

2-2. componentDidMount

이 API는 주로 외부 라이브러리를 연동하거나 컴포넌트에서 필요로 하는 데이터 요청을 하거나(ex: ajax, graphQL)
DOM에 관련된 작업(ex: 스크롤 설정, 크기 읽어오기)을 할때 사용한다.

conponenetDidMount {
	console.log('componentDidMount');
}

둘다 console.log를 해봤을 때 나오는 순서는 아래와 같다. (맨 위 사진 참고)

console

contructor
conponentDidMount

2-3 etc... (componentWillMount)

componentWillMount는 컴포넌트가 화면에 나가나기 직전에 호출되는 API 인데요, 이 API 에 대해선 별로 신경쓰지 않아도 된다고 한다. 원래는 주로 브라우저가 아닌 환경에서 (서버사이드)도 호출하는 용도로 사용했었는데, 이 API 가 더 이상 필요하지 않게 되어 리액트 v16.3 에서는 해당 API가 사라지게 되었으니... 아, 옛날엔 이러한 API가 사용됐었구나.. 하고 알아만 두면 된다.

3. 컴포넌트 업데이트

3-1. static getDerivedStateFromProps()

이 API 는 props 로 받아온 값을 state 로 동기화 하는 작업을 해줘야 하는 경우에 사용된다.

  static getDerivedStateFromProps(nextProps, prevState) {
    // nextProps는 다음으로 받아올 props 값을 뜻함
    // prevState는 현재 업데이트 되기전 상태를 가져옴
    if (prevState.value !== nextProps.value) {
      return {
        value: nextProps.value
      };
    }
    // 변경할 사항이 없으면 return null
    return null;
  }

getDerivedStateFromProps(nextProps, prevState) 메서드는 static 키워드를 붙여서 인스턴스 메서드로 선언해야 한다.

첫번째 인자(nextProps) 는 부모 컴포넌트로 부터 전달받는 객체이며,
두번째 인자(prevState) 는 렌더링되기 이전의 state 객체다.
getDerivedStateFromProps() 메서드를 선언하고 따로 return 하지 않을 경우에는 warning이 발생하게 된다.
return 하는 데이터는 객체여야 한다.

render() 메서드가 호출되기 전이므로, 변경 된 props 데이터를 state에 반영하는 작업을 이 메서드에서 처리하면 된다.

메서드 호출 시점

컴포넌트 최초 마운트 시에는 호출되지 않는다.
props, state 업데이트가 발생하여 render() 메서드가 호출된 뒤 즉시 호출되는 메서드다.

3-2. shouldComponentUpdate()

nextPropsnextState를 파라미터로 가져온다. return false를 하게 되면 업데이트를 안하게 된다.
따로 구현하지 않는다면 return true가 default값이 되고 특정 상황에 따라 false값을 넣어줄수도 있다.
특정 조건에 따라 업데이트를 막아줄 수 있는 함수라고 생각해도 된다.

//App.js
class App extends Component {
  state = {
    counter: 1
  };

  constructor(props) {
    super(props);
    console.log('constructor');
  }
  componentDidMount() {
    console.log('componenetDidMount');
  }
  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };
  render() {
    return (
      <div>
        <MyComponent value={this.state.counter} />
        <button onClick={this.handleClick}>click me</button>
      </div>
    );
  }
}
// MyComponent.js
shouldComponentUpdate(nextProps, nextState) {
    if (nextProps.value === 10) return false;
    return true;
  }
render() {
  return (
    <div>
      <p>props: {this.props.value}</p>
      <p>props: {this.state.value}</p>
    </div>
  );
}

숫자를 증가시키는 버튼이 있다고 하면 버튼을 계속 누르다가 10에서 멈추게 된다. 하지만 한번 더 누르면 11이 나오게 되는데 if문에 value값이 10과 같다면 false를 return하고 또 다시 누르게 되면 11이기 떄문에 true 값으로 나와서 11이 나오게 된다.

3-3. getSnapshotBeforeUpdate()

이 API가 발생하는 시점은 다음과 같다.
컴포넌트가 업데이트 되서 브라우저의 dom에 반영되기 직전에 호출된다. 어떤식으로 쓰이냐면 업데이트 되기 바로 직전에 DOM 상태를 리턴시켜서 리턴된 값을 컴포넌트에 업데이트해서 받아올수있다.

1. render()
2. getSnapshotBeforeUpdate()
3. 실제 DOM 에 변화 발생
4. componentDidUpdate

이 API를 통해서, DOM 변화가 일어나기 직전의 DOM 상태를 가져오고, 여기서 리턴하는 값은 componentDidUpdate 에서 3번째 파라미터로 받아올 수 있게 됩니다.

스크롤 예시

3-4. componentDidUpdate()

componentDidUpdate(prevProps, prevState, snapshot) {

}

이 API는 컴포넌트에서 render() 를 호출하고난 다음에 발생하게 됩니다. 이 시점에선 this.props 와 this.state 가 바뀌어있습니다. 그리고 파라미터를 통해 이전의 값인 prevProps 와 prevState 를 조회 할 수 있습니다. 그리고, getSnapshotBeforeUpdate 에서 반환한 snapshot 값은 세번째 값으로 받아옵니다

4. 컴포넌트 제거

4-1. componentWillUnmount

componentWillUnmount() {
  // 이벤트, setTimeout, 외부 라이브러리 인스턴스 제거
}

여기서는 주로 등록했었던 이벤트를 제거하고, 만약에 setTimeout 을 걸어 놓은 것이 있다면 clearTimeout 을 통하여 제거를 한다. 추가적으로, 외부 라이브러리를 사용한게 있고 해당 라이브러리에 dispose 기능이 있다면 여기서 호출해주면 된다.

5. 컴포넌트 에러 발생

5-1. componentDidCatch()

자식 컴포넌트에 먼저 정의 되지 않은 missing.something을 넣어주고 부모 컴포넌트인 App.js에 componentDidCatch를 작성해보겠다.

  componentDidCatch(error, info) {
    console.log(error);
    console.log(info);
  }

이 API를 사용하면 우리가 실수로 잡지 못했던 에러들을 잡는데 유용하며 예를 들면 실사용자들에게 에러가 났습니다 라는 문구를 보여줄수도 있다.

에러를 넣어서 직접 구현해보자.

// MyComponent.js
class MyComponent extends Component {
  render() {
    return (
      <div>
        {this.props.missing.something} //에러 시점
        <p>props: {this.props.value}</p>
        <p>props: {this.state.value}</p>
      </div>
    );
  }
}

export default MyComonent

{this.props.missing.something}로 정의 되지 않은 props를 불러와서 일부러 에러를 줬다.
componentDidCatch로 setState안에 error:true값을 넣어주고 render()안에 if문으로 error가 true값이 된다면
<div>에러 발생 !</div>를 return하게 해준다.

// App.js
class App extends Component {
  state = {
    counter: 1,
    error: false
  };
  componentDidCatch(error, info) {
    this.setState({
      error: true
      // API를 통해서 서버로 오류 내용 날리기
    });
  }
   render() {
      if (this.state.error) {
        return <div>에러 발생 !</div>;
      }
      return (
        <div>
          <MyComponent value={this.state.counter} />
          <button onClick={this.handleClick}>click me</button>
        </div>
      );
   }
}

export default App;

이 API 를 사용하시게 될 때 주의할 점은 컴포넌트 자신의 render 함수에서 에러가 발생해버리는것은 잡아낼 수는 없지만, 그 대신에 컴포넌트의 자식 컴포넌트 내부에서 발생하는 에러들을 잡아낼 수 있다.

이렇게 많은 API를 사용하려니 일단 겁은 나지만 나 사나이 홍두현 여기서 쓰러질 수 없다.
예제를 통해 좀 더 확실히 개념을 가져가자.

다음 게시글은 예제를 바탕으로 진행해보자 🔥🔥🔥

profile
마음이 시키는 프론트엔드.. RN과 IOS를 곁들인..

2개의 댓글

comment-user-thumbnail
2022년 3월 14일

두현님 글 너무 잘 쓰시는것 같아요 재밌고 이해하기 쉽고 최고!!

1개의 답글