State와 LifeCycle(생명주기)

HyunHo Lee·2021년 12월 9일
0

프론트

목록 보기
39/55
post-thumbnail

class 변환

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 함수에 JSX 문법으로 엘리먼트를 생성했었다. 그리고 여기서 ReactDom.render 해주었다.

이번에는 시계 기능만 캡슐화 해볼 것이다.


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

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

Clock부분을 Class Component로 만들었다. 현재 <Clock date={new Date()} /> 와 같이 Clock Component를 사용하고 있고, props를 사용하기 위해 date를 넘겨주고 있다. 캡슐화는 정보 은닉이 핵심인데, 이 경우에는 props의 데이터가 사용자에게 노출될 수 있다.

render 메서드는 업데이트가 발생할 때마다 호출되지만, 같은 DOM 노드로 을 렌더링하는 경우 Clock 클래스의 단일 인스턴스만 사용됩니다. 이것은 로컬 state와 생명주기 메서드와 같은 부가적인 기능을 사용할 수 있게 해줍니다.


class에 로컬 State 추가하기

먼저 state가 무엇인지 부터 알아보자.

State는 props처럼 데이터를 갖고있는 객체이다. 위에서 props는 date={new Date()} 와 같이 전달하고 있었다.

state는 함수 안에서 선언된 변수처럼 컴포넌트 안에서 관리된다는 차이가 있다. 이러한 캡슐화로 정보은닉을 하고, 사용하는 부분과 구현하는 부분을 명확하게 나눌 수 있다.


  • class에 로컬 State 추가

그럼 이제 date를 props에서 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>
    );
  }
}

Clock의 render()의 변수 가져오는 부분을 this.props에서 this.state으로 바꿔주었다.

그리고 component의 생성자 메소드인 constructor을 사용했다. Component를 초기화 시켜주는 작업이다. (state를 사용하기 위해)


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

<Clock />와 같이 사용할수 있게 되어 date prop를 빼주었다.

실행해보니 시간이 멈춰버렸다. setInterval(tick, 1000); 부분을 없애버렸기 때문이다.

이제 Clock이 매초 스스로 업데이트하도록 만들기만 하면 완성이다.


LifeCycle 메서드 추가

Clock이 처음 DOM에 렌더링 될 때마다 타이머를 설정하려고 한다. 이것을 'Mount' 라고 한다. React에서 componentDidMount() 을 사용한다.

그리고 Clock에 의해 생성된 DOM이 삭제될 때마다 타이머를 해제해야한다. 이것은 'UnMount' 라고 한다. React에서 componentWillUnmount() 을 사용한다.

이런 것들이 바로 LifeCycle(생명주기) 메소드 이다.


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

componentDidMount() 메서드는 Component 출력물이 DOM에 렌더링 된 후에 실행된다. 즉, 이 메서드가 호출되는 시점은 우리의 컴포넌트가 화면에 나타난 상태이다.

this.props 의경우 this.props.date 와 같이 타고 내려가며 사용했다. this.state도 이와 유사하게 사용되지만, 타이머처럼 데이터 흐름 안에 포함되지 않는 항목을 보관할 경우에는 class에 자유롭게 추가해도 된다. this.timerID가 그 예시이다.

DOM에 직접 이벤트를 등록하는것이 아닌 외부 라이브러리 연동, 데이터요청(axios나 fetch로 ajax 요청)에도 사용한다.


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

componentWillUnmount()는 Component가 화면에서 사라지기 직전에 호출된다. DOM에 직접 등록했었던 이벤트를 제거하는 작업을 해줘야한다. (setInterval을 사용했으므로 clearInterval로 해제하자.)

외부 라이브러리를 사용했을 경우, dispose 기능이 있는 라이브러리는 여기서 호출하자.


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

constructor에서 this.state의 date에 new Date() 넣어줬었다. 지금의 시간을 바로 출력해준 것이다.

그리고 1초마다 tick() 함수로 불러주기 위해 componentDidMount() 을 사용했고, componentWillUnmount()로 clearInterval 하고있다.

이제 tick()에서는 this.state의 date에 new Date()를 넣어준다면, 1초마다 new Date() 불러와 시계처럼 작동할 것이다.

state를 변경하기 위해서는 this.setState를 사용한다.


//전체 코드
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, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

이제 실행해보면 시계가 동작한다.

시간이 변경될때마다 푸른 선으로 깜빡거리고 있다. 이것은 렌더링을 시키고 있다는 의미이다.

Hello, world!부분도 계속 렌더링을 시켜줘야할까? 좋아보이지는 않는다.


ReactDOM.render(
  <>
    <h1>Hello, world!</h1>
    <Clock />
  </>
  ,
  document.getElementById('root')
);

Clock Component에 있던 h1태그를 빼주었다. 이제 시간이 바뀔 때, 해당 부분만 렌더링되는것을 볼 수 있다.


State 올바르게 사용하기

// this.state.comment = 'Hello'; 잘못된 방법

this.setState({comment: 'Hello'});

State값을 직접 변경할 수 있는곳은 constructor 뿐이다. 나머지 부분에서는 setState를 사용하자.


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

state와 props의 값을 이용해서 counter의 값을 변경해주고 있다. 여기서는 state와 props 앞에 this를 붙이면 안된다. this.props와 this.state는 비동기적으로 업데이트될 수 있기 때문이다.

화살표 함수말고 일반 함수로도 사용 가능하다.

profile
함께 일하고 싶은 개발자가 되기 위해 달려나가고 있습니다.

0개의 댓글