안경잡이개발자

React의 State

리액트(React)2018. 12. 25. 08:47
728x90
반응형

  이번 시간에는 리액트(React)의 상태(State)에 대해서 알아보도록 하겠습니다. 이 state는 고정적인 데이터가 아니라 변경될 수 있는 데이터를 처리할 때 효율적으로 사용될 수 있습니다. 재미있는 점은 실제로 state 값을 변경해서 화면(View)이 변경되면 render() 함수가 다시 실행되어 실제로 화면에 적용을 해준다는 점입니다.


  또한 state를 사용하기 위해서는 이전 시간까지 작성했던 함수형 컴포넌트 대신에 클래스형 컴포넌트를 사용하셔야 합니다. props만 이용하고자 한다면 함수형 컴포넌트를 그대로 사용하세요. 다시 말해서 내부 객체의 값이 변경될 여지가 있다면 클래스형 컴포넌트로 state를 사용하고, 그렇지 않다면 props를 사용하시면 됩니다.


  이전 시간에는 예제로 초 시계 렌더링(Rendering) 사례를 다룬 적 있습니다.


※ HTML 소스코드 ※


<div id="root"></div>


※ JavaScript 소스코드 ※


function tick() {

  const element = (

    <h3>현재 시각은 [{new Date().toLocaleTimeString()}] 입니다.</h3>

  );

  ReactDOM.render(element, document.getElementById('root'));

}

setInterval(tick, 1000);


  일단 이 구성을 지난 시간에 배운 props를 활용해 보다 객체지향적으로 바꾸어 봅시다.



※ JavaScript 소스코드 ※


function Clock(props) {

  return (

    <h3>현재 시각은 [{props.date.toLocaleTimeString()}] 입니다.</h3>

  );

}


function tick() {

  ReactDOM.render(

    <Clock date={new Date()}/>, 

    document.getElementById('root')

  );

}

setInterval(tick, 1000);



  현재 보이는 이러한 구성은 tick()이라는 특정한 함수 안에서 ReactDOM의 렌더링 함수를 불러오는 형식입니다. 이러한 방식보다 더 체계적인 구현 방식은 특정한 컴포넌트 안에서 render() 함수를 이용하여 렌더링이 수행되도록 하는 것입니다. 그러기 위해서는 Component 클래스를 상속 받아야 합니다. Component 클래스에는 내부적으로 render() 함수가 포함되어 있습니다.


※ JavaScript 소스코드 ※


class Clock extends React.Component {

  render() {

    return (

      <h3>현재 시각은 [{this.props.date.toLocaleTimeString()}] 입니다.</h3>

    );

  }

}


function tick() {

  ReactDOM.render(

    <Clock date={new Date()}/>, 

    document.getElementById('root')

  );

}

setInterval(tick, 1000);



  이로써 Clock 클래스의 인스턴스 하나만 사용되는 형태로 구현이 완료되었습니다. 다만 여기에서 생성자(Constructor)를 이용해서 Clock 클래스 멤버 변수로서 Date 객체를 처리하도록 하면 더욱 객체 지향적일 것입니다. 바로 이 때 상태(State)가 사용됩니다.


  또한 state를 사용할 때는 반드시 생성자를 만들어 주어서 state에 대한 초기화를 진행해주셔야 합니다.


※ JavaScript 소스코드 ※


class Clock extends React.Component {

  constructor(props) {

    super(props);

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

  }

  

  render() {

    return (

      <h3>현재 시각은 [{this.state.date.toLocaleTimeString()}] 입니다.</h3>

    );

  }

}


ReactDOM.render(

  <Clock />, 

  document.getElementById('root')

);



  위 코드를 보시면 props가 state로 대체된 것을 확인할 수 있습니다. 실제로 이와 같이 특정한 값이 계속 변경되는 형태를 보일 때는 보통 state을 사용하게 됩니다. 하지만 현재 state 값이 변경되는 로직이 코드에 없습니다. state는 props와 다르게 부모 컴포넌트에서 값을 넘겨주는 형태로 사용되지 않기 때문이에요. 그래서 위 소스코드는 실행했을 때 실제로 시간이 변경되지 않습니다. 또한 추가적으로 알아두어야 할 것은 state 값을 수정하고자 할 때는 setState() 함수를 이용해야 한다는 점입니다.


  따라서 컴포넌트 라이프 사이클 함수를 이용하시면 됩니다. 이전에 props를 사용할 때는 미리 Date 객체를 생성해서 자식 컴포넌트인 Clock 컴포넌트에게 데이터를 보내주어야 했지만 state를 이용하게 되면 내부적으로 데이터를 함수에 의해서 처리하게 됩니다. 반면에 props는 컴포넌트 내부 함수를 이용해서 변경될 수 없다는 특징이 있어요. 결과적으로 우리는 state 값을 변경하기 위해서 컴포넌트 라이프 사이클을 이용하게 될 것입니다. 컴포넌트 라이프 사이클에 대한 자세한 내용은 다음 시간에 진행하게 되며, 일단 간단히 예제를 알아보도록 해요.


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 (

      <h3>현재 시각은 [{this.state.date.toLocaleTimeString()}] 입니다.</h3>

    );

  }

}


ReactDOM.render(

  <Clock />, 

  document.getElementById('root')

);


  결과적으로 다시 다음과 같이 1초에 한 번씩 시간 데이터가 갱신되는 것을 확인할 수 있습니다.



  따라서 state를 사용하는 이유에 대해서 더욱 자세히 알아보기 위해 버튼 이벤트가 발생할 때마다 특정한 객체의 값이 변경되는 사례를 확인해보도록 하겠습니다. 현재 시각을 처음에 한 번 기록해 놓은 뒤에, 특정 버튼을 누를 때마다 시각이 10초씩 뒤로 밀려나도록 처리하겠습니다.


class Clock extends React.Component {

  constructor(props) {

    super(props);

    this.state = {

      date: new Date()

    }

  }

  

  goBack() {

    let nextDate = this.state.date;

    nextDate.setSeconds(nextDate.getSeconds() - 10);

    this.setState({

      date: nextDate

    });

  }

  

  render() {

    return (

      <div>

        <h3>현재 시각은 [{this.state.date.toLocaleTimeString()}] 입니다.</h3>

        <button onClick={this.goBack.bind(this)}>10초 뒤로가기</button>

      </div>

    );

  }

}


ReactDOM.render(

  <Clock />, 

  document.getElementById('root')

);



  기본적으로 우리가 사용하고 있는 ES6 문법에서는 자동으로 함수가 바인딩 처리 되지 않습니다. 그래서 직접 메소드를 바인딩 처리 해주셔야 하며 바인딩을 하지 않는 경우 리액트 객체가 정상적으로 처리되지 않습니다.


  (+ 추가)

  state의 개념을 지금 한 번에 이해할 필요는 없습니다. 추후에 프로젝트 예제를 다루면서 state를 사용하면 보다 깔끔하게 이해할 수 있을 거예요. 대략 이런 개념이 있다는 것 정도만 이해하고 넘어가세요.

728x90
반응형