Dev/SW Engineering

24. React - 12 main concepts(State & Lifecycle)

HJChung 2020. 7. 21. 13:03

(+ React에 대해 공부한 것을 정리한 것입니다. 배우는 중이라 잘못된  내용이 있을 수 있으며 계속해서 보완해 나갈 것입니다. :))

앞서 

React의 주요 개념 중

4. Component와 Pros

에 대해서 정리해 보았다.  

 

이번에는 

React의 주요 개념 중

5. State & Lifecycle

에 대해서 정리해볼 것이다. 

React의 주요 개념들

5)  State & Lifecycle

1. State

이전 Component와 Pros를 정리한 포스트에서 " name='Sara', name='Grace'에 해당하는 props는 읽기 전용값으로, 함수 component나 클래스 component 모두 component의 자체 props를 수정해서는 안 된다. 그래서 React에서는 State를 통해 동적인 UI를 구현할 수 있게 한다. State에 대해서는 다음 포스트에서 정리할 것이다." 라고  했었다. 

 

즉, State는 Props를 함께 생각하면서 개념을 정리하면 좋을 것 같다. 

  • component가 있고,
  • component의 속성으로 props 제공해주어서 해당 component의 내용을 조작하거나 상태를 관리할 수 있다.  
  • props처럼 (외부에서) 주어지는게 아닌 component "내부적으로" 상태를 관리할 때 사용되는 것이 state이다. 

component를 사용시 외부에서 주어지는 props과, props에 따라 component를 실행시 작동하는 내부의 state이 철저히 분리되어 있어야 한다. 

 

아래 예시 코드를 보면서 state가 어떻게 쓰이는지 확인해보자. 

① 시작

HTML 파일

<div id="root"></div> 
<!--이 안에 들어가는 모든 엘리먼트를 React DOM에서 관리하기 때문에 이것을 “루트(root)” DOM 노드라고 부르고, 
React로 구현된 애플리케이션은 일반적으로 하나의 루트 DOM 노드가 있다.-->

JS 파일

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);

이 코드를 실행하면 매 초마다 <h2><h2>It is {new Date().toLocaleTimeString()}.</h2>이 부분이 다른 새로운 Element가 전달될텐데, 아래처럼 잘 화면에 변경사항이 잘 반영된다. 

위의 코드에서 이 부분을 Clock component로 만들면 앞 포스팅 4. Component와 Pros의 <② Components의 용도>에서 살펴본것 처럼 '재사용성'과 '유지보수의 편리함'을 얻을 수 있다.

const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );

② 위의 코드 Clock component로 캡슐화

(State 설명하다가 갑자기 왜 캡슐화? 라고 생각할 수도 있지만 이 과정에서 state의 필요성이 나오고, 그 때 state의 사용법에 대해서 정리할 거라서 그렇다. 바로 아래(③ 그래서, props를 사용하지 않고, Clock component가 스스로 업데이트하도록 하려면 )에 나온다!

내가 이 플로우로 state를 이해했기때문에..)

그래서 저 부분을 Clock component로 캡슐화하면 

JS 파일

이렇게 setInterval에 맞춰서 date값이 props로 외부에서 주어지는 형태가 된다 .

그리고 "props는 읽기 전용값으로, component의 자체 props를 수정해서는 안 된다." 고 한 점을 기억하자. props로 주어졌으면 그걸 쓰고 끝! 이다. 

 

③ 그래서, props를 사용하지 않고, Clock component가 스스로 업데이트하도록 하려면 

세 단계에 걸쳐서 date를 props에서 state로 이동한다. 

※ state를 사용하기 위해선, class 컴포넌트로 작성되어야 한다.

1. render() 메서드 안에 있는 this.props.date를 this.state.date로 변경

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

2. 초기 this.state를 지정하는 class constructor를 추가

※ constructor의 역할: 어떤 component가 실행될 때, render()보다 먼저 실행되면서, 그 component를 초기화 시켜주고 싶은 것으로 constructor(){ 여기서 코드를 작성한다.}

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

3. <Clock /> 요소에서 date prop을 삭제. 더이상 필요 없으니까. 

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

그러면 state를 사용한 코드

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

이렇게 된다. 

여기까지만 실행하면 state를 도입했고, constructor에서 component를 초기화 시킨 것 까지만 한 것이다. 그래서 

 

이 표시된 시간 부분인 state값이 초기화 시켜준 값으로 되었고, 

 

 

state값의 업데이트는 되고 있지 않아서 화면이 변하지 않고 저 상태로 고정되어있다.

 

state를 업데이트 시켜주기 위해선 어떻게 해야할까??state 값을 변경하려고 한다면, setState 메서드를 이용한다. 그리고 setState 메서드를 사용해서 state값을 변경하면, render()함수가 다시 실행된다.

 

그런데 그 전에 Lifycycle을 먼저 살펴보고, setState를 사용한 state 업데이트를 해보자. 

2. Lifecycle

Lifecycle은 component의 생명주기를 말하며, 페이지에 렌더링 되기 전 준비과정에서 시작해서 페이지에서 사라질 때 끝난다. 위에서 예시로 계속 사용했던 Clock component의 Lifecycle을 생각해보면 Clock component가 DOM에 렌더링 될 때마다 타이머가 설정되고, 작동되다가,  DOM에서 사라질 때마다 작동이 멈추는 것이 되지않을까?

그리고 이렇게 생명주기가 끝나면 많은 컴포넌트가 있는 애플리케이션에서 컴포넌트가 삭제될 때 해당 컴포넌트가 사용 중이던 리소스를 확보할 수도 있다. 

 

React에서는 이 렌더링 상황에 따라 작동되는 것을 mount / unmount 라고 부른다.

그래서 Clock component의 Mounting은 'DOM에 렌더링 될 때마다 타이머를 설정' 하는 것이고 componentDidMount 메서드를 사용해서 작동시킬 수 있다. 

또한 Clock component의 Unmounting은 Clock에 의해 생성된 DOM이 삭제될 때마다 타이머를 해제하는 것이고, componentWillUnmount 메서드를 사용한다. 

 

그래서 앞과 이어서 

4. Clock이 스스로 타이머를 설정하고 매초 스스로 업데이트하도록 하려면 아래와 같이 Mount관련 메서드와 Setstate 메서드를 쓸 수 있다, 

class Clock extends React.Component {
  constructor(props) { //2. React는 Clock 컴포넌트의 constructor를 호출한다. 
    super(props);
    this.state = {date: new Date()}; //3. Clock이 현재 시각을 표시해야 하기 때문에 현재 시각이 포함된 객체로 this.state를 초기화한다.
  }

  componentDidMount() { //6. Clock 출력값이 DOM에 삽입되면, React는 componentDidMount() 생명주기 메서드를 호출한다.
  //그 안에서 Clock 컴포넌트는 매초 컴포넌트의 tick() 메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청한다.
    this.timerID = setInterval(
      () => this.tick(), // 7. 매초 브라우저가 tick() 메서드를 호출한다. 
      1000
    );
  }

  componentWillUnmount() {//10. Clock 컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면 React는 타이머를 멈추기 위해 componentWillUnmount() 생명주기 메서드를 호출한다. 
    clearInterval(this.timerID);
  }

  tick() {//8.그 안에서 Clock 컴포넌트는 setState()에 현재 시각을 포함하는 객체를 호출하면서 UI 업데이트를 진행한다.   
    this.setState({//setState() 호출 덕분에 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 render() 메서드를 다시 호출
      date: new Date()
    });
  }

//9. 이 때 render() 메서드 안의 this.state.date가 달라지고 렌더링 출력값은 업데이트된 시각을 포함하고. React는 이에 따라 DOM을 업데이트한다.
  render() { //4. React는 Clock 컴포넌트의 render() 메서드를 호출하고
    return ( // 5. 아래 내용 즉, React는 화면에 표시되어야 할 내용을 알게 된다. 
      <div> 
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2> //6.그 다음 React는 Clock의 렌더링 출력값을 일치시키기 위해 DOM을 업데이트한다.  
      </div>
    );
  }
}

ReactDOM.render(//1. <Clock />가 ReactDOM.render()로 전달되었을 때
  <Clock />, 
  document.getElementById('root')
);

이제 실행시켜보면, 시간이 흐르면서 화면이 바뀐다. 

 

정리!

① Component 생성 과정

Component가 생성되면(작성된 컴포넌트가 호출되면)

⇒ Constructor가 호출된다.

⇒ Component 내에서 render 메소드가 호출된다.

⇒ 그러면 JSX를 반환하여 화면에 그려지는 과정이 되고(화면 rendering)

⇒ 그게 끝나면 componentDidMount()가 불린다.

 

 

 

 

② State값이 변경되거나 해서 Component가 업데이트 될 때

 

 

state값이 변경되면(setState)

⇒ render 메소드가 실행되고

⇒ 업데이트된 값이 화면에 보여지고(화면 rendering)

⇒ 그게 끝나면 componentDidUpdate()가 불린다.

 

 

 

 

복잡해 보이지만 위의 코드와 하나씩 비교해가며 보면 Lifecycle와 React 작동 flow 이해에 도움이 많이 되었던 표이다. 

지금까지 

React의 주요 개념 중

5. State & Lifecycle

에 대해서 정리해 보았다.  

 

다음은 

React의 주요 개념 중

6. Handling Event

에 대해서 정리해볼 것이다. 

 

reference

ko.reactjs.org/docs/state-and-lifecycle.html

https://youtu.be/rOpg2KUPW2M

상현님 블로깅 글