React[Component] - Lifecycle(2)

일상 코딩·2022년 5월 7일
0

React

목록 보기
11/45
post-thumbnail
post-custom-banner

01.Component Lifecycle 변경 (Version 16.3 이상)

Component Initialization & Mounting

  • constructor
  • componentWillMount => getDerivedStateFromProps
  • render
  • componentDidMount

Component Updation

  • componentWillReceiveProps => getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • componentWillUpdate => getSnapshotBeforeUpdate
  • DOM에 적용
  • componentDidUpdate

Component Unmounting

  • componentWillUnmount

02.getDerivedStateFromProps

  • DOM에서 요소들이 랜더링 되기 직전에 호출된다.
  • 최초의 props 에 기반한 state 객체를 저장한다.
  • state를 인자로 받고, state가 변하면 객체를 반환한다.
  • 이 메소드는 시간이 흐름에 따라 변하는 props에 state가 의존하는 아무 드문 사용례를 위하여 존재합니다.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Example</title>

  <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>  
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<body>
  <div id="root"></div>
	<script type="text/babel">
   
class App extends React.Component {
  state = {
    age: 24,
  }

  interval = null;

  constructor(props) {
    super(props)

    console.log("constructor", props)
  }
  render() {
    console.log("render")
    return (
      <div>
        <h2>
          Hello {this.props.name} - {this.state.age}
        </h2>
      </div>
    )
  }

  static getDerivedStateFromProps(nextProps, prevState) {
  console.log("getDerivedStateFromProps", nextProps, prevState);

  return {
    age: 390,
  }
}

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

    this.interval =  setInterval(() => {
      this.setState(state => ({...state, age: state.age + 1}))
    }, 1000);
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("shouldComponentUpdate", nextProps), nextState;

    return true;
  }
 
  componentDidUpdate(prevProps, prevState) {
    console.log("componentDidUpdate", prevProps, prevState);
  }

  componentWillUnMount() {
     clearInterval(this.interval);
  }
}

    ReactDOM.render(<App name="Mark" />, document.querySelector("#root"))
  </script>	
	</body>
</html>

실행 결과

  • $ npx serve

03.getSnapshotBeforeUpdate

이 메소드는 업데이트 되기 전의 propsstate에 접근할 수 있다.

  • 즉, update 이후에도 update 이전의 값들을 확인할 수 있다는 것을 의미한다.
  • 만약 getSnapshotBeforeUpdate() 메소드가 존재하면 componentDidUpdate() 메소드도 포함해야 한다. 그렇지 않으면 에러가 발생한다.
  • 이 메소드에 대한 사용례는 흔하지 않지만, 채팅 화면처럼 스크롤 위치를 따로 처리하는 작업이 필요한 UI 등을 생각해볼 수 있습니다.
  • 스냅샷 값을 반환하거나 null을 반환합니다.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Example</title>

  <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>  
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<body>
  <div id="root"></div>
	<script type="text/babel">
let i=0;

class App extends React.Component {
  state = { list: []};

  render() {
    return (
      <div id="list" style={{ height: 100, overflow: "scroll" }}>
        {this.state.list.map((i) => {
          return <div>{i}</div>;
        })}
      </div>
    );
  }

  componentDidMount() {
    setInterval(() => {
      this.setState((state) => ({
        list: [...state.list, i++],
      }));
    }, 1000);
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevState.list.length === this.state.list.length) return null;
    const list = document.querySelector("#list");
    return list.scrollHeight - list.scrollTop;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log(snapshot);
    if (snapshot === null) return;
    const list = document.querySelector("#list");
    list.scrollTop = list.scrollHeight - snapshot;
  }
}
    ReactDOM.render(<App name="Mark" />, document.querySelector("#root"))
  </script>	
	</body>
</html>
  • getSnapshotBeforeUpdate를 이용하여 데이터가 업데이트하게 되면 스크롤 위치가 자동으로 변하게 되는 로직을 구현한 코드입니다.

실행 결과

  • $ npx serve

04.componentDidCatch

  • 자손 컴포넌트에서 오류가 발생했을 때에 호출되는 메소드입니다.
  • 해당 라이프사이클이 나오기 전에는 리액트 앱으로 부분적으로 에러가 발생했을 때, 전체 웹사이트가 동작하지 않는 문제가 있었습니다.
  • 하지만 이제는 componentDidCatch로 해당 컴포넌트로 오류가 발생하게 되면 해당 화면을 보여줄 수 있게 되었습니다.
  • 그러나 해당 라이프사이클의 단점은 자손 컴포넌트가 아닌 자기 자신에게 오류가 발생하게 되면 오류를 캐치할 수 없게 됩니다.
  • 그렇기 때문에 에러 바운더리를 가장 부모로 만들어주고 그 하위인 서비스 컴포넌트에서 문제가 발생했을 때에 캐치하는 방식으로 사용하게 됩니다.
  • 그러므로 이 경우에는 에러 바운더리라는 라이브러리를 사용해야 합니다.
class App extends React.Component {
  state = {
    hasError: false,
  };

  render() {
    if (this.state.hasError) {
      return <div>예상치 못한 에러가 발생했다.</div>;
    }

    return <WebService />;
  }

  componentDidCatch(error, info) {
    this.setState({ hasError: true });
  }
}
profile
일취월장(日就月將) - 「날마다 달마다 성장하고 발전한다.」
post-custom-banner

0개의 댓글