React

[React] 동빈나 React 이론 - 5강 / React의 State(상태)

sangchu 2022. 8. 7. 03:36

props는 부모에서 자식 Component로 데이터를 전달하고자 할 때 사용할 수 있다.

일반적으로 고정적인 데이터 값을 전달할 때 사용한다.

 

state는 고정적인 데이터가 아닌, 변경될 수 있는 데이터를 처리할 때 효율적으로 사용된다.

다른 말로, 하나의 웹 사이트가 구상된 이후에도 내부적인 데이터가 계속해서 변경될 수 있는 경우(내부 객체 값이 변경될 여지가 있는 경우)에 효과적으로 사용된다.

 

state 값을 변경해서 화면(view)이 변경되면 render() 함수가 다시 실행되어 실제 화면에 적용해준다.

 

props만 이용하고자 한다면 함수형 컴포넌트를 사용했다.

그러나 state를 사용한다면 Class형 컴포넌트로 사용해야한다.

 


아래 코드는 3강에서 사용한 시계 코드이다.

function tick() {
  const element = (
  <h3>현재 시각은 [{new Date().toLocaleTimeString()}] 입니다.
      </h3>
    )
  ReactDOM.render(element, document.getElementById("root"));
}
 
setInterval(tick,1000);

 

아래 코드는 위 코드를 더 객체지향적으로 만든 것이다.

화면을 구성하는 부분도 함수형 컴포넌트로 분리했다.

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

function tick() { // 렌더링 수행
  ReactDOM.render(<Clock date={new Date()}/>, document.getElementById("root"));
}

setInterval(tick,1000);

 

구조적으로 좋아졌으나 이 코드도 효과적인 방식은 아니다.

 

 

더 뛰어난 구현 방식은 ReactDOM의 render함수가 수행되는 것이 아닌,

Component 안에서 render() 함수를 이용해 렌더링이 수행될 수 있도록 하는 것이다.

그러기 위해선 Component Class를 상속 받아야한다.

Component Class에는 내부적으로 render() 함수가 포함되어 있다.

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

Class형 컴포넌트는 기본적으로 props를 내장하고 있다. 

따라서 this 키워드를 사용하여 해당 컴포넌트에 내장된 Props를 이용해 출력하도록 만들어야 한다.(매개변수에 props를 넣어줄 필요가 없다)

 

 

class Clock extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      date: new Date() // 새롭게 만든 Date 객체를 date라는 변수에 넣어줌
    };
  }
  
  render() {
    return(
      <h3>현재 시각은 [{this.state.date.toLocaleTimeString()}] 입니다.</h3>
    );
  }
}

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

state를 적용하면 constructor를 이용하여 생성자를 명시해야한다.

기본적으로 생성자를 명시 안해주면 자동으로 props를 사용할 수 있는 형태인데

굳이 명시하면 super 키워드를 이용하여 props로 전달 받은 것을 초기화해줘야 한다.

 

state는 특정 Class가 내부적으로 가지고 있는 변수로

자기 자신이 내부적으로 가지고 있는 date객체를 이용해서 현재 시간을 출력할 수 있도록 만들면 된다.

 

계속 특정한 내부적인 값이 변경되는 경우 state를 쓴다고 했다.

위 코드는 state에서 데이터 값 새롭게 갱신된느 로직 없어서 시간 멈춰보인다.

이제 setInterval 안쓴다. → 클락 클래스 컴포넌트에서 정의하면 끝임 → 더 간결

라이프사이클 이용해 내부적으로 처리할 수 있도록 만들어야한다.

 

 

class Clock extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      date: new Date() // 새롭게 만든 Date 객체를 date라는 변수에 넣어줌
    };
  }
  tick(){
    this.setState({
      date: new Date() // 새로운 new Date로 바꿔치기
    })
  }
  componentDidMount(){
    this.timerID = setInterval(()=> this.tick(), 1000); // 변경된 date값 감지
  }
  componentWillUnmount(){
    clearInterval(this.timerID);
  }
  
  render() {
    return(
      <h3>현재 시각은 [{this.state.date.toLocaleTimeString()}] 입니다.</h3>
    );
  }
}

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

componentDidMount() : 컴포넌트가 초기화가 끝났을 때, 즉 마운트가 끝났을때 자동으로 불러와주는 함수

componentWIllUnmount(): 리소스 낭비 없애기 위해, 컴포넌트가 어마운트 될 떄(이용이 끝났을때)

이전에는 props를 통해 외부에서 데이터를 전해주는 형태,

이제는 state를 이용해서 clock 클래스 내부에서 상태를 계속해서 바꾸어 줌으로써 화면을 갱신

 

 

class Clock extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      date: new Date() // 새롭게 만든 Date 객체를 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>
          <!-- bind 처리해야지 해당 함수 사용 가능 -->
      </div> 
     );
  }
}

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

초기화할때 this.state에 어떠한 변수에 어떤 값을 넣는다고 정의할 수 있는데,

이후에 state값을 변경하고싶을땐 setState함수를 사용해야함

사용안하면 코드상의 오류는 없지만 , 작동안함