4 분 소요

1. 16.3 이전 Component Lifecycle

  • React Component는 탄생부터 죽음까지 여러 지점에서 개발자가 작업이 가능하도록 메서드를 오버라이딩 할 수 있게 해줌
  • Declarative 성질 : Component의 탄생부터 죽음까지 순간순간을 선언적으로 표현하면, React Component가 선언적으로 표현된 함수들을 실행해서 사용할 수 있게 해주기 때문에, 효과적으로 처리할 수 있음
  • Initialization
    • setup props and state
  • Mounting
    • componentWillMount
    • render
    • componentDidMount
  • Updation
    • props
      • componentWillReceiveProps
      • shouldComponentUpdate
      • componentWillUpdate
      • render
      • componentDidUpdate
    • states
      • shouldComponentUpdate
      • componentWillUpdate
      • render
      • componentDidUpdate
  • Unmounting
    • componentWillUnmount


- Component 생성 및 마운트

  • constructor
  • componentWillMount
  • render (최초 랜더)
  • componentDidMount
<body>
  <div id="root"></div>
  <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    console.log(React);
    console.log(ReactDOM);

    class App extends React.Component {
      state = {
        age: 29,
      };
      constructor(props) {
        super(props);
        console.log('consturctor', props);
      }
      render() {
        console.log('render')
        return (
          <div>
            <h2>Hello {this.props.name} - {this.state.age}</h2>
          </div>
        );
      }
      componentWillMount() {
        console.log('componentWillMount');
      }
      componentDidMount() {
        console.log('componentDidMount');

        // 타이머 설정
        setInterval(() => {
          this.setState(state => ({ ...state, age: state.age + 1}));
        }, 1000);
      }
    }

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


react-lifecycle1


- Component props, state 변경

  • componentWillReceiveProps
    • props를 새로 지정했을 때 바로 호출됨
    • state의 변경에 반응하지 않음
    • props의 값에 따라 state를 변경해야 한다면,
      • setState를 이용해 state를 변경
      • 각각 다음 이벤트로 가는것이 아니라 한번에 변경됨
  • shouldComponentUpdate
    • props만, state만, props와 state 둘다 변경되어도 실행
    • new Props와 new State를 인자로 해서 호출
    • return type이 boolean
      • true면 render
      • false면 render가 호출되지 않음
      • 이 함수를 구현하지 않으면, default는 true
  • componentWillUpdate
    • Component가 재 rendering되기 직전에 호출
    • setState 같은 것을 쓰면 안됨
  • render
  • componentDidUpdate
    • Component가 재 rendering을 마치면 호출
<body>
  <div id="root"></div>
  <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    console.log(React);
    console.log(ReactDOM);

    class App extends React.Component {
      state = {
        age: 29,
      };
      constructor(props) {
        super(props);
        console.log('consturctor', props);
      }
      render() {
        console.log('render')
        return (
          <div>
            <h2>Hello {this.props.name} - {this.state.age}</h2>
          </div>
        );
      }
      componentWillMount() {
        console.log('componentWillMount');
      }
      componentDidMount() {
        console.log('componentDidMount');

        // 타이머 설정
        setInterval(() => {
          this.setState(state => ({ ...state, age: state.age + 1}));
        }, 1000);
      }

      componentWillReceiveProps(nextProps) {
        console.log('componentWillReceivePorps', nextProps);
      }
      shouldComponentUpdate(nextProps, nextState) {
        console.log('shouldComponentUpdate', nextProps, nextState);
        return true;  // 바로 render할 준비
        // return false;  // props나 state가 변경되어도 다시 render하지 않음
      }
      componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate', nextProps, nextState)
      }
      componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate', prevProps, prevState)
      }
    }

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


  • ShouldComponentUpdate가 false일 경우

react-lifecycle2


  • ShouldComponentUpdate가 true 경우

react-lifecycle3


- Component 언마운트

  • componentWillUnmount
    • 언마운트되기 직전
    • Component가 사용하고 있던 메모리 중에 정리할 것이 있으면 정리
    • API 응답을 받기 전에 언마운트 된다면 API를 더 이상 받을 준비를 하지 않는 처리 등

<body>
  <div id="root"></div>
  <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    console.log(React);
    console.log(ReactDOM);

    class App extends React.Component {
      state = {
        age: 29,
      };
      // 변수 정의
      interval = null;
      constructor(props) {
        super(props);
        console.log('consturctor', props);
      }
      render() {
        console.log('render')
        return (
          <div>
            <h2>Hello {this.props.name} - {this.state.age}</h2>
          </div>
        );
      }
      componentWillMount() {
        console.log('componentWillMount');
      }
      componentDidMount() {
        console.log('componentDidMount');
        
        // 멤버 변수로 할당
        this.interval = setInterval(() => {
          this.setState(state => ({ ...state, age: state.age + 1}));
        }, 1000);
      }

      componentWillReceiveProps(nextProps) {
        console.log('componentWillReceivePorps', nextProps);
      }
      shouldComponentUpdate(nextProps, nextState) {
        console.log('shouldComponentUpdate', nextProps, nextState);
        return true;
      }
      componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate', nextProps, nextState)
      }
      componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate', prevProps, prevState)
      }
      // Interval 함수 종료
      componentWillUnmount() {
        clearInterval(this.interval);
      }
    }

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


2. 16.3 이후 Component Lifecycle

  • Initialization
    • setup props and state
  • Mounting
    • getDerivedStateFromProps
    • render
    • componentDidMount
  • Updation
    • props
      • getDerivedStateFromProps
      • shouldComponentUpdate
      • render
      • getSnapshotBeforeUpdate(DOM에 적용)
      • componentDidUpdate
    • states
      • shouldComponentUpdate
      • render
      • getSnapshotBeforeUpdate(DOM에 적용)
      • componentDidUpdate
  • Unmounting
    • componentWillUnmount


- Component 생성 및 마운트

  • constructor
  • getDerivedStateFromProps
    • 시간의 흐름에 따라 변하는 Props에 State가 의존하는 경우 사용
  • render
  • componentDidMount
<body>
  <div id="root"></div>
  <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    console.log(React);
    console.log(ReactDOM);

    class App extends React.Component {
      state = {
        age: 29,
      };
      interval = null;
      constructor(props) {
        super(props);
        console.log('consturctor', 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: 100
        };
      }
      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="LWW" />, document.querySelector("#root"));
  </script>
</body>
</html>


react-lifecycle4


- Component props, state 변경

<body>
  <div id="root"></div>
  <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    console.log(React);
    console.log(ReactDOM);

    let i = 0 ;

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

      render() {
        return (
          <div id="list" style=>
            {this.state.list.map(i => {
              return (<div>{i}</div>);
            })}  
          </div>
        );
      }
      componentDidMount() {
        setInterval(() => {
          this.setState(state => ({
            list: [ ...state.list, i++],
          }));
        }, 1000);
      }
      getSnapshotBeforeUpdate(prevPorps, prevState) {
        if (prevState.list.length === this.state.list.length) {
          return null;
        }
        const list = document.querySelector('#list');
        return list.scrollHeight - list.scrollTop;
      }
      componentDidUpdate(prevPorps, prevState, snapshot) {
        console.log(snapshot);
        if (snapshot === null) {
          return;
        }
        const list = document.querySelector('#list');
        list.scrollTop = list.scrollHeight - snapshot;
      }
    }
    
    ReactDOM.render(<App name="LWW" />, document.querySelector("#root"));
  </script>
</body>
</html>


react-lifecycle5


- Component 에러 캐치

  • componentDidCatch
<body>
  <div id="root"></div>
  <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    console.log(React);
    console.log(ReactDOM);
    
    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 });
      }
    }

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

댓글남기기