TIL React_03 (State)

백광호·2021년 2월 10일
0

TIL

목록 보기
49/55

State

state는 리액트에서 사용하는 JavaScript의 객체와 같다.
이런 state를 사용하기 위해서는 클래스 컴포넌트에서 작성해야 한다.

클래스 컴포넌트안에서 state를 사용할 수 있다.
state는 컴포넌트에 데이터를 넣을 수 있고 이 데이터를 변경할 수 있다.

여기서 잠깐 porps와 state의 차이점을 간단하게 설명하자면
props는 외부로부터 전달받은 값이며 변경할 수 없고
state는 내부에서 변경할 수 있는 값이다.

위에서 설명했듯 state는 클래스 컴포넌트에서 사용해야 되는데
함수 컴포넌트를 클래스 컴포넌트로 변환하는 것도 알아두면 좋다.

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

이와 같은 함수 컴포넌트를 클래스 컴포넌트로 변환하면 아래와 같이 변환할 수 있을 것 같다.

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

변환하는 과정은 다음과 같다.

  • React.Componenet를 확장하는 동일한 이름의 ES6 클래스를 생성한다.
  • render()라고 불리는 빈 메소드를 추가한다.
  • 함수의 내용을 render() 메소드 안으로 옮긴다.
  • render() 내용 안에있는 propsthis.props로 옮긴다.

이제 이 Clock은 함수가 아닌 클래스가 된다.

다음으로 여기에 로컬 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>
    );
  }
}

두가지를 추가해줬다. 첫번째는 this.props.datathis.state.data로 변경했다.
두번째는 constructor(props)(생성자)를 추가했다.
그리고 초기 this.state를 지정해줬다.
생성자를 추가할 때 super()를 사용해 생성자의 속성을 상속받아왔다.
클래스 컴포넌트는 항상 props로 기본 생성자를 호출해야 한다.

이제 이 클래스 컴포넌트를 리액트 DOM에 렌더링하면 된다.

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

State 사용법

setState()에 대해서 알아둬야할 것이 3가지 있다.

  1. 직접 State를 수정하지 말아야 한다.
  2. State는 비동기적으로 움직일 수 있다.
  3. State 업데이트는 병합된다.

이중 첫번째 직접 State를 수정하지 말아야 한다가 제일 중요하다.

class ToggleSwitch extends React.Component{
  constructor(props) {
    super(props);
    this.state = {isOn: false};
}

이런 클래스 컴포넌트가 있고 this.state가 생성되어 있다고 가정한다.
이 state를 수정하기 위해 아래 처럼 작성하는 실수를 많이 하곤 한다.

this.state.isOn = true

이런식으로 작성할 경우 state를 직접 수정하지 말라는 경고가 뜨게 된다.
반드시 state를 수정할 때에는 아래처럼 작성하여 수정해야된다.

this.setState({isOn: true})

왜 이렇게 해야될까?

만약 setState를 사용하지 않으면 내가 값을 바꿔도
새로운 state와 함께 render()메소드가 호출되지 않는다.

state를 직접 수정할 경우 이미 렌더링한 컴포넌트의 값을 바꾸지만
setState를 통해 수정할 경우 기존의 state를 버리고
변경된 부분을 새로 렌더링 하기 때문이다.

이벤트 처리하기

HTML에서 이벤트를 다룰때에는 아래와 같이 다루게 된다.

<button onclick="activateLasers()">
  Activate Lasers
</button>

리액트에서 이벤트를 다룰 때에는 아래와 같이 다루게 된다.

<button onClick={activateLasers}>
  Activate Lasers
</button>

둘의 차이점을 살펴보면 다음과 같다.

  • 리액트의 이벤트는 소문자대신 캐멀 케이스(camelCase)를 사용한다.
  • JSX를 사용하여 문자열이 아닌 함수로 이벤트 핸들러를 전달한다.

클래스 컴포넌트를 이용해 정의할 때, 일반적인 패턴은 이벤트 핸들러를 클래스의 메소드로 만든다.
아래 Toggle 컴포넌트 예제는 사용자가 ON, OFF 상태를 토글할 수 있는 버튼을 랜더링 한다.

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 콜백에서 `this`가 작동하려면 아래와 같이 바인딩 해주어야 합니다. 왜일까요?
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

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

JSX 콜백 안에서 this의 의미에 대해 살펴보자.
JavaScript에서 클래스 메소드는 기본적으로 바인딩되어 있지 않다.
this.handleClick을 바인딩 하지 않고 onClick에 전달 한다면
함수가 호출될 때 this는 undefined가 된다.

이런 현상은 리액트만의 특수한 동작이 아니며,
JavaScript에서 함수가 작동하는 방식의 일부이다.

일반적으로 onClick={this.handleClick}과 같이 뒤에 ()를 사용하지 않고
메소드를 참조할 경우 해당 메소드를 바인딩 해줘야된다.

bind는 호출 시 this 키워드를 제공된 값으로설정하는 새로운 함수를 만든다.
위 예제에서는 Toggle을 bind함수로 추가하고 콜백이 실행될 때 Toggle을 참조한다.

state의 구분

state의 위치를 파악할때 생각해야될 것으로
state가 어디서 사용되는지를 생각해봐야 한다.

이를 구분하는데에는 절대적인 기준이나 법칙이 있는것은 아니지만
JavaScript를 배울 때처럼 로컬 state, 전역 state로 나눠서 접근하면 이해하기 쉬울 것이다.

  • 로컬 state

특정 컴포넌트 안에서만 관리되는 상태
다른 컴포넌트와 데이터를 공유하지 않는 form 데이터는 대부분 로컬 state이다.
input box, select box, radio button 등을 이용한 state가 대표적이다.

  • 전역 state

프로덕트 전체 혹은 여러가지 컴포넌트가 동시에 관리하는 상태

서로 다른 컴포넌트가 사용하는 state의 종류가 다르다면 출처가 달라도 상관 없다.
하지만 서로 다른 컴포넌트가 동일한 상태를 다룰 때에는,
서로 다른 출처로 가져오는 것은 피해야 한다.

만일 사본이 있을 경우 두 데이터는 서로 동기화 하는 과정이 필요한데
이는 문제를 더 어렵게 만들게 된다.
한곳에서만 state를 저장하고 접근해야 한다.

이는 데이터 무결성을 위한 것인데 여기서 데이터 무결성이란,
데이터의 정확성을 보장하기 위해 데이터의 변경이나 수정 시 제한을 두어
안정성을 저해하는 요소를 막고 데이터 상태들을 항상 옳게 유지하는 것을 말한다.

전역 state를 사용할 때에는 반드시 동일한 데이터는 항상 같은 곳에서
데이터를 가지고 오도록 해야 한다.

Single Source of truth(신뢰할 수 있는 단일 출처)원칙은 프론트 엔드 뿐만 아니라
다양한 곳에서도 언급되는 원칙이다.

전역 state로 관리되어야 하는 state의 대표적인 예들

  • 웹사이트의 라이트모드(밝은 테마)/다크모드(어두운 테마)
  • Globalization 설정(브라우저, OS 언어설정)
  • 포토샵, 일러스트레이터의 히스토리 기능
  • Undo/Redo
profile
안녕하세요

0개의 댓글