Back to the Basics

[React] React-State and Lifecycle 본문

Frontend Development/React

[React] React-State and Lifecycle

9Jaeng 2021. 8. 11. 00:31
728x90

이 포스트는 React 공식문서를 참고하여 작성하였습니다.

State 란?

  • state는 component 내에서 변할 수 있는 값이다.
    예를 들어, 쇼핑몰에서 제품을 선택하는 체크박스를 예로 들 수 있다. 여기서 상태는 체크박스를 checked 상태와 uncheck 한 상태로 볼 수 있다.
  • state는 local 또는 캡슐화라고도 불리며 **state가 소유하고 설정한 component 이외의 component도 접근할 수 없다.
  • 부모 -> 자식 의 하향식 (단방향식 이라고도 불림)의 데이터 흐름만 가능하다 : 어떤 하나의 component는 자식 component의 props로 그것의 state를 넘겨줄 수 있다.
  • state는 특정한 component에 의해 소유되며 , 이 state로부터 파생된 데이터 또는 UI 등은 Tree 구조에서 아래에 있는 component에만 영향을 미칠 수 있다

Porps Vs State

  • state는 데이터를 갖는 객체의 형태라는 점에서 props와 비슷하지만, private이며 전적으로 component에 의해 제어된다.
  • props는 함수 매개변수처럼 copmpoent에 전달되는 반면 state는 함수 내에 선언된 변수처럼 component 안에서 관리된다.

위의 설명 만으로는 이해하기 어렵다. 위의 공식문서에서 설명한 코드를 빌려 하나하나 살펴보자.

class Clock extends React.Component {

  // 클래스 생성자 (class constructor)를 넣는다. 
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }


  // Lufe Cycle (생면주기 메서트)를 추가한다

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }


  // setState()를 호출하여 component의 state객체에 대한 업데이트를 실행한다.

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


  // state를 랜더링한다. 화면에 표시되어야 할 내용들.
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}


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

위의 코드의 Clock 은 class형 component이며, 현재 시간 설정하고 1초마다 시간을 업데이트를 스스로 하는 component이다.

위 코드의 실행 순서를 먼저 보면 아래와 같다.

  1. React.render 에서 이 전달되었으므로 React는 Clock의 생성자(constructor)를 호출한다.
    --> 현재 시각이 포함된 객체로 this.state를 초기화한다.
  2. React는 Clock component의 render() 메서드를 호출하고 DOM을 업데이트한다.
  3. React는 생명주기 메서드인 componentDidMount()를 호출한다. 이 메서드는 매 초마다 component의 tick() 메서드를 호출한다.
  4. 매초 브라우저는 tick()을 호출하고 이 메서드(tick())은 steState()에 현재 시각을 포함하는 객체를 호출하면서 UI를 업데이트한다.
    --> 이때 render() 안의 this.state.date가 달라지고 DOM은 업데이트된다.
  5. Clock component가 DOM으로부터 한 번이라도 삭제된 적이 있다면 componentWillCunmount() 생명주기 메서드를 호출한다.

이제 각 순서와 코드를 같이 보면서 아래의 개념들을 알아보자.

Contructor (생성자)와 super(props)

constructor(props){
  super(props);
  this.state={date:new Date()};
}

초기의 this.state를 지정하는 클래스 생성자를 추가한다. 이 생성자에 의해서 현재의 시각을 포함하는 객체로 this.state를 초기화하고 Clock은 현재 시각을 표시할 수 있게 된다.

super란??

  • super는 JavaScript에서 부모 class 생성자를 참조하는 키워드이다.
  • 자바스크립트는 클래스 생성자에서 super 호출 전에 this를 사용하지 못한다는 언어적 제약사항이 있다.
    그 이유와 super(props)에 대한 상세 설명을 이 포스트를 참고하자 Why Do We Write super(props)?

super의 인자로 props를 넣는 이유는?

  • React Component 객체가 생성될 때 props 속성을 초기화하기 위해 부모 component에 props를 전달한다.
  • super()에 인자로 props를 넣지 않아도 Reac는 생성사 호출 이후에 prop속성을 setting 해주기 때문에 실수로 빠뜨려도 정상적으로 동작은 된다. 하지만 super()만 실행하는 경우 생성자가 호출되고 끝나기 전까지 this.props === undefined 이기 때문에 내부에서 this.props의 사용은 불가능하다. 그렇기 때문에 super(props)로 호출하는 것이 바람직하다고 한다..!

Life Cycle (생명주기)


// mount lifecycle
componentDidMount(){
  this.timerID=sterInterval(()=>this.tick(), 1000));
}

// unmount lifecycle
componentwillUnmount(){
  clearInterval(this.timerID);
}
  • 위의 코드는 Clock이 처음 DOM에 렌더링이 될 때마다 타이머를 설정하는 코드와 Clock에 의해 생성된 DOM이 삭제될 때마다 타이머를 해제하는 코드이다. 전자는 Mounting이라고 하고 후자는 Unmounting이라고 한다. 이와 같은 메서드를 Lifecycle methode(생명주기 메서드)라고 한다.
  • componentDiMount()는 component 출력이 DOM에 렌더링 된 후에 실행이 된다.
  • 코드에서 this.timerID같이 데이터 flow 안에는 포함되지 않는 어떠한 것을 저장해야 할 때 클래스에 부가적인 필드를 추가해도 된다.
  • ( 왜 그런가 생각을 해보니, 부모 클래스를 상속받은 것이고, 자식 클래스는 상속받은 부모 클래스에 추가적으로 더 만들기가 가능하기 때문.. 인가?)

setInterval()

  • MDN문서에 의하면 setInterval()은 설정한 time delay로 함수 또는 코드 snippet을 반복적으로 호출한다.
  • interval을 고유하게 식별하는 interval ID를 반환하고 이 ID로 clearInterval()를 호출하여 제거할 수 있다.
  • 위의 코드에서 setInterval(()=> this.tick(),1000))은 1초마다 tick()을 반복적으로 호출한다.

clearInterval

  • 위에서 설명했듯이, clearIntercal(intercalID) method는 호출된 setInterval을 제거한다.
  • return value : undefined

setState()

setState()

tick() {
  this.setState({
    date: new Date()
    {);
}
  • setState(updater, [calback])
  • setState()는 Event handler, server response로 인한 UI 업데이트를 하기 위해 사용한다.
  • Component의 state 변화를 대기열에 추가하고 React에 re-rendering을 하도록 알려준다.
  • 위의 코드는 component의 state 객체에 대한 업데이트를 실행한다. 현재 시각과 함께 setStater가 호출되면 React는 state가 변했음을 인지한다.
  • local state를 업데이트하기 위해 setState()를 사용한다.

Note!!!

  • State를 직접적으로 수정하면 안 된다.
    • this.state.comment="Wrong"; // Wrong!!!
    • this.setState({comment:"Goooooood"}); // Correct!!
    • this.satte에 직접 할당할 수 있는 곳은 constructor이다.
  • state update는 비동기적일 수 있다.
    • this.state와 this.props는 비동기적으로 업데이트가 될 수 있다.
this.setState({
  counter: this.state.counter + this.props.increment,
});

위의 코드와 같이 작성하게 되면 아마 업데이트에 실패할 수도 있다.( this.state 와 props의 업데이트가 동기적으로만 일어나는 것이 아니기 때문에)

이를 수정하려면 아래와 같이 코드를 작성한다

this.setState((state,props)=>({
  counter:state.counter+props.increment
}));

위의 코드는 객체가 아닌 함수를 인자로 사용하였다. 첫 번째 인자는 이전의 state이고 두 번째 인자는 업데이트가 적용된 시점의 props이다.

State updates are Merged

setState()를 call 할 때 React는 제공한 객체를 current state로 병합한다.

constructor(props){
    super(props);
    this.state={
        title:[],
        introcuce:[]
    };
}



componentDidMount() {
    fetchTitle().then(response => {
      this.setState({
        title: response.title
      });
    });

    fetchintro().then(response => {
      this.setState({
        introduce: response.introduce
      });
    });
  }

병합은 shallow(얕게) 이루어지기 때문에 this.setState({title})은 thie.state.introduce에 영향을 주지 않지만 this.state.title은 완전히 대체된다.

728x90
Comments