PROGRAMMING/React

React :: 생λͺ…μ£ΌκΈ° (Lifecycle)

\b\t 2021. 3. 21. 18:33

생λͺ…μ£ΌκΈ° λ©”μ„œλ“œ

클래슀 Component μ—μ„œ 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œλ₯Ό μ„ μ–Έν•˜μ—¬ μ»΄ν¬λ„ŒνŠΈκ°€ λ§ˆμš΄νŠΈλ˜κ±°λ‚˜ μ–Έλ§ˆμš΄νŠΈ 될 λ•Œμ˜ μ‹€ν–‰ν•  μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

즉 Component κ°€ 보여지고, 사라지고, μ—…λ°μ΄νŠΈ 될 λ•Œ ν˜ΈμΆœλ˜λŠ” API 이닀.

 

맀우 μ€‘μš”ν•˜κ³ , μ‚¬μš©ν•˜λ©΄ 효율적인 ν”„λ‘œκ·Έλž˜λ°μ„ ν•  수 μžˆμœΌλ‹ˆ 잘 λ΄λ‘μž.

 

componentDidMount()

μ»΄ν¬λ„ŒνŠΈ μΆ”λ ₯물이 처음 DOM 에 λ Œλ”λ§ 된 후에 μ‹€ν–‰λ˜λŠ” ν•¨μˆ˜.

주둜 μ™ΈλΆ€ λΌμ΄λΈŒλŸ¬λ¦¬μ™€μ˜ 연동, Component μ—μ„œ ν•„μš”ν•œ 데이터 μš”μ²­ 등을 여기에 μž‘μ„±ν•œλ‹€.

componentDidMount() {
  //DOM 에 처음 Component κ°€ λ Œλ”λ§ 될 λ•Œ 싀행됨
}

componentWillUnmount()

마운트된 μ»΄ν¬λ„ŒνŠΈκ°€ DOM μœΌλ‘œλΆ€ν„° ν•œ λ²ˆμ΄λΌλ„ μ‚­μ œλœ 적 μžˆλ‹€λ©΄ React λŠ” 이 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€.

주둜 setTimeout 을 걸어놓은걸 μ—†μ• κ±°λ‚˜, 이벀트 처리, μ™ΈλΆ€ 라이브러리 μΈμŠ€ν„΄μŠ€ 제거 등을 여기에 μž‘μ„±ν•œλ‹€.

componentWillUnmount(){
    //DOM μ—μ„œ Component κ°€ μ‚­μ œλ˜λ©΄ 싀행됨
}

 

shouldComponentUpdate(nextProps, nextState)

이 λ©”μ„œλ“œλŠ” μ΅œμ ν™”ν•˜λŠ” 데에 많이 μ‚¬μš©ν•œλ‹€.

React μ—μ„œ μ–΄λ–€ μ»΄ν¬λ„ŒνŠΈκ°€ λ¦¬λ Œλ”λ§λ˜λ©΄ (μ—…λ°μ΄νŠΈλ˜λ©΄) , κ·Έ μ»΄ν¬λ„ŒνŠΈμ˜ μžμ‹ μ»΄ν¬λ„ŒνŠΈλ“€λ„ λ¦¬λ Œλ”λ§λœλ‹€.

(λ Œλ”λ§λœλ‹€λŠ” 것은 render() ν•¨μˆ˜κ°€ μ‹€ν–‰λœλ‹€λŠ” 것이닀)

 

λ¬Όλ‘  λ³€κ²½ 상항이 μ—†λ‹€λ©΄ μ‹€μ œ DOM μ‘°μž‘μ€ μΌμ–΄λ‚˜μ§€ μ•Šλ‹€. 단지 Virtual DOM 에 λ Œλ”λ§μ„ μˆ˜ν–‰ν•  뿐이닀.

κ·Έλ ‡λ‹€λ©΄ μžμ‹ Component κ°€ λ§Žλ‹€λ©΄, 그만큼 μžμ›μ„ μ‚¬μš©ν•΄μ„œ λΆ€μˆ˜μ μΈ, μ“Έλ°μ—†λŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ²Œ 될 수 μžˆλ‹€.

 

λ”°λΌμ„œ μ—…λ°μ΄νŠΈκ°€ ν•„μš”ν•˜μ§€ μ•ŠλŠ” Component 의 경우 이 λ©”μ„œλ“œμ—μ„œ false λ₯Ό λ°˜ν™˜ν•΄μ£Όλ©΄ λœλ‹€.

default λŠ” true λ₯Ό λ°˜ν™˜ν•˜μ—¬, μ—…λ°μ΄νŠΈλ₯Ό μˆ˜ν–‰ν•˜μ§€λ§Œ false λ₯Ό λ°˜ν™˜ν•œλ‹€λ©΄ ν•΄λ‹Ή μ‘°κ±΄μ—μ„œλŠ” λ¦¬λ Œλ”λ§, 즉 render() 을 ν˜ΈμΆœν•˜μ§€ μ•Šκ²Œ λ˜λŠ” 것이닀.

shouldComponentUpdate(nextProps, nextState){
  return true; // default
  // return false;
}

 

componentDidUpdate(prevProps, prevState, snapshot)

이 λ©”μ„œλ“œλŠ” Component μ—μ„œ render() 을 ν˜ΈμΆœν•˜κ³  λ‚œ 뒀에 ν˜ΈμΆœλœλ‹€.

이 μ‹œμ μ—μ„œλŠ” props 와 state κ°€ λ°”λ€Œμ–΄μžˆκΈ° λ•Œλ¬Έμ—, 인자둜 prevProps 와 prevState λ₯Ό λ³Ό 수 μžˆλ‹€.

snapshot 값은 getSnapshotBeforeUpdate() λ©”μ„œλ“œμ—μ„œ λ°˜ν™˜ν•œ 값이닀.

 

 

getSnapshotBeforeUpdate()

이 λ©”μ„œλ“œλŠ” render() 호좜 ν›„, μ‹€μ œ DOM 에 μ—…λ°μ΄νŠΈν•˜κΈ° 전에 ν˜ΈμΆœλœλ‹€.

즉, λ‹€μŒκ³Ό 같은 과정이 Component Update μ‹œ μ‹€ν–‰λœλ‹€.

  1. λ Œλ”λ§ (render())
  2. getSnapshotBeforeUpdate()
  3. μ‹€μ œ DOM 에 μ—…λ°μ΄νŠΈ (λ³€ν™”)
  4. componentDidUpdate()

이 λ©”μ„œλ“œλ₯Ό 톡해 DOM λ³€ν™”κ°€ μΌμ–΄λ‚˜κΈ° μ§μ „μ˜ DOM μƒνƒœλ₯Ό κ°€μ Έμ™€μ„œ componentDidUpdate() μ—μ„œ 확인할 수 있게 λœλ‹€.

 


예제

React 곡식 λ¬Έμ„œμ— λ‚˜μ™€μžˆλŠ” μ‹œκ³„ 타이머 예제λ₯Ό 직접 ν•΄λ³΄μž.

μ•„λž˜μ˜ tick Component λŠ” μ‹œκ°„μ΄ λ³€ν•˜λŠ” 것을 1000ms λ§ˆλ‹€ μ—…λ°μ΄νŠΈ ν•΄μ£ΌλŠ” κΈ°λŠ₯을 μˆ˜ν–‰ν•œλ‹€.

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

그런데 tick Component λŠ” μ»΄ν¬λ„ŒνŠΈμ˜ κΈ°λŠ₯을 μ™ΈλΆ€μ—μ„œ μ œμ–΄ν•΄μ£Όκ³  μžˆλ‹€.

 

κ·Έλž˜μ„œ 이λ₯Ό λ‹€μŒμ˜ μš”κ΅¬μ‚¬ν•­μ— 맞게 λ³€κ²½ν•˜κ³ μž ν•œλ‹€.

  • Component 슀슀둜 타이머λ₯Ό μ„€μ •
  • Component 슀슀둜 맀초 μ—…λ°μ΄νŠΈ
  • ν•˜λ„λ‘ μ™„μ „νžˆ μΊ‘μŠν™”ν•˜κΈ°!

μ΄μ œλΆ€ν„° 이 μš”κ΅¬ 사항을 λ§Œμ‘±μ‹œν‚€λŠ” Clock Component λ₯Ό μž‘μ„±ν•  것이닀.

 

μš°μ„  슀슀둜 타이머λ₯Ό μ„€μ •ν•˜κΈ° 제일 쒋은 μ‹œμ μ€ componentDidMount() 이고, 타이머λ₯Ό 멈좜 μ‹œμ μ€ componentWillUnmount() κ°€ μ λ‹Ήν•˜λ‹€.

즉, Clock Component κ°€ 처음 DOM 에 λ Œλ”λ§λ˜λŠ” μ‹œμ μ— 타이머λ₯Ό μ„€μ •ν•˜κ³ , Clock Component κ°€ DOM μ—μ„œ μ‚­μ œλ˜λŠ” μ‹œμ μ— 타이머λ₯Ό ν•΄μ œν•˜λ €λŠ” 것이닀.

componentDidMount(){
    this.timerId = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount(){
    clearInterval(this.timerId);
  }

this.props κ°€ React 에 μ˜ν•΄ 슀슀둜 μ„€μ •λ˜κ³ , this.stateκ°€ νŠΉμˆ˜ν•œ μ˜λ―Έκ°€ μžˆμ§€λ§Œ

데이터 흐름 μ•ˆμ— ν¬ν•¨λ˜μ§€ μ•ŠλŠ” ν•­λͺ©μ„ 보관할 ν•„μš”κ°€ μžˆλ‹€λ©΄,

μ—¬κΈ° this.timerID 처럼 자유둭게 ν΄λž˜μŠ€μ— μˆ˜λ™μœΌλ‘œ 뢀가적인 ν•„λ“œλ₯Ό 좔가해도 λœλ‹€.

 

그리고 props 둜 name 을 λ°›μ•„μ„œ "Hello, {name}!" 을 보여주고, "It is {μ‹œκ°„}" ㅇ을 보여쀄 것이닀.

λ”°λΌμ„œ, 1000ms 둜 λ³€ν™”ν•˜λŠ” μ‹œκ°„μ€ Clock μ»΄ν¬λ„ŒνŠΈμ˜ state 둜 가지고, name 은 porps μ—μ„œ 쀄 것이닀.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date()
    };
  }
//μ€‘λž΅//
}

그럼 μ΄λŸ¬ν•œ ν˜•νƒœκ°€ λ˜κ² λ‹€.

state 으둜 μ‹œκ°„μ„ 담아쀄 date λ₯Ό μ •μ˜ν•˜μ˜€λ‹€.

 

그럼 이 date λ₯Ό 1000ms λ§ˆλ‹€ μ—…λ°μ΄νŠΈν•΄μ•Ό ν•˜λŠ”λ°, setState() 둜 date λ₯Ό μ—…λ°μ΄νŠΈν•  tick() ν•¨μˆ˜λ₯Ό μž‘μ„±ν•˜μž.

tick(){
    this.setState({
      date: new Date()
    });
}

이제 λ‹€ λ˜μ—ˆλ‹€. 전체 μ½”λ“œλ₯Ό 보고 흐름을 μ •λ¦¬ν•΄λ³΄μž.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date()
    };
  }
  componentDidMount(){
    this.timerId = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount(){
    clearInterval(this.timerId);
  }
  tick(){
    this.setState({
      date: new Date()
    });
  }
  render() {
    return (
      <div>
        <h1>Hello, {this.props.name} !</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock name="React"/>,
  document.getElementById('root')
);
  1. ReactDOM μ—κ²Œ Clock μ»΄ν¬λ„ŒνŠΈκ°€ props = {name: "React"} 둜 μ „λ‹¬λ˜λ©°, Clock μ»΄ν¬λ„ŒνŠΈμ˜ constructor λ₯Ό ν˜ΈμΆœν•œλ‹€.
  2. constructor μ—μ„œ this.state λ₯Ό μ΄ˆκΈ°ν™”ν•œλ‹€.
  3. React λŠ” Clock μ»΄ν¬λ„ŒνŠΈμ˜ render() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€. 이λ₯Ό 톡해 React λŠ” 화면에 ν‘œμ‹œν•  λ‚΄μš©μ„ μ•Œκ²Œ λœλ‹€.
  4. React λŠ” Clock 의 λ Œλ”λ§ 좜λ ₯값을 μΌμΉ˜ν•˜κΈ° μœ„ν•΄ DOM 을 μ—…λ°μ΄νŠΈν•œλ‹€.
  5. Clock 좜λ ₯값이 DOM 에 μ‚½μž…λ˜λ©΄ React λŠ” componentDidMount() μƒλͺ…μ£ΌκΈ° λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€.
    (κ·Έ μ•ˆμ—μ„œ 타이머λ₯Ό μ„€μ •ν•œλ‹€. -λΈŒλΌμš°μ €μ— 타이머 μš”μ²­)
  6. 타이머λ₯Ό μ„€μ •ν•œ λŒ€λ‘œ, 맀초 λΈŒλΌμš°μ €κ°€ tick() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄μ„œ setState() λ₯Ό 톡해 ν˜„μž¬ μ‹œκ°„μ„ ν¬ν•¨ν•˜λŠ” 객체λ₯Ό ν˜ΈμΆœν•˜μ—¬ UI μ—…λ°μ΄νŠΈλ₯Ό μ§„ν–‰ν•œλ‹€.
  7. setState() λ₯Ό 톡해 React λŠ” state κ°€ λ³€ν™”ν•œ 것을 μΈμ§€ν•˜κ²Œ 되고, 화면에 ν‘œμ‹œλ  (λ³€κ²½λœ) λ‚΄μš©μ„ μ•Œμ•„λ‚΄κΈ° μœ„ν•΄ render() λ©”μ„œλ“œλ₯Ό λ‹€μ‹œ ν˜ΈμΆœν•œλ‹€.
    (이 λ•Œ 달라진 this.state.date λ₯Ό DOM 에 μ—…λ°μ΄νŠΈν•œλ‹€.)
  8. Clock μ»΄ν¬λ„ŒνŠΈκ°€ DOM μœΌλ‘œλΆ€ν„° ν•œ λ²ˆμ΄λΌλ„ μ‚­μ œλœ 적이 μžˆλ‹€λ©΄ React λŠ” componentWillUnmount() μƒλͺ…μ£ΌκΈ° λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€.
    (-> 타이머가 λ©ˆμΆ”κ²Œ λœλ‹€.)

λ‚˜λŠ” React CRA 둜 μƒˆ App 을 λ§Œλ“€μ—ˆμ„ λ•Œ μžλ™μœΌλ‘œ μƒκΈ°λŠ” ./my-app/src/App.js μ—μ„œ 이 Clock μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μž‘μ„±ν•΄μ£Όμ—ˆλ‹€.

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        <div>
          <Clock name="React"/>	// here!!
        </div>
      </header>
    </div>
  );
}

κ·Έ κ²°κ³Ό μ•„λž˜μ™€ 같은 결과물을 얻을 수 μžˆμ—ˆλ‹€.

기쑴의 React ν™”λ©΄μ—μ„œ this.props.name κ³Ό 맀초 λ³€ν™”ν•˜λŠ” μ‹œκ°„μ„ 좜λ ₯ν•  수 μžˆλ‹€.

 


Reference

React 곡식 λ¬Έμ„œ ko.reactjs.org/docs/state-and-lifecycle.html

.