본문 바로가기
카테고리 없음

React - 상태(가변 상태 - state)

by 최고영회 2019. 3. 13.
728x90
반응형
SMALL

이전글: 2019/03/03 - [IT/React] - React - 상태 (기본)


리액트 애플리케이션을 개발하려면 데이터를 다루는 방법에 더 많은 시간을 집중해서 투자해야 한다. 

'상태' 란 무엇일까

 - 특정 시점에 프로그램이 사용하고 있는 정보 

 - 다시 말해 상태는 어느 특정 시점에 프로그램에 대해 알고 있는 것(추가 대입이나 연산 없이 참조할 수 있는 모든 값)들의 스냅샷이다. 


실행중인 프로그램이 어느 정도 복잡해지면 그 상태를 파악하기가 더 어려워진다. UI를 개발하는 데는 특히 더 어렵다.

리액트는 데이터를 다루는 두가지 props와 state를 제공하여 UI가 가지는 복잡성을 줄이거나 그런 복잡성으로 부터 우리를 보호하는데 도움을 준다.


1. 가변 데이터 (컴포넌트 내에서 변경 가능한 데이터) : '상태'

 - 파일을 '저장' 하는 기능이라고 생각하면 쉽다. (덮어쓰기)

2. 불변 데이터 (컴포넌트가 변경할 수 없으며, 수신만 가능한 데이터) : '속성' 

 - 파일을 '다른 이름으로 저장' 하는 기능이라고 생각하면 쉽다. (복사본 저장)


비록 자바스크립트가 본질적으로 완전한 불변 데이터 구조를 제공하지는 못하지만, 리액트는 컴포넌트의 '상태'를 가변객체로 다루며 

'속성'은 읽기 전용으로 다룬다. 


상태를 변경하는 예제 코드를 살펴 보자. 

 - 통상적으로 아래 예제에서 사용한 setState 메서드는 성능과 복잡도 문제로 인해 가능하면 보조적으로 사용하는 것을 권장한다. 

 - 나중에 살펴볼 리덕스 몹스, 플럭스 등의 다양한 패턴들을 이용하는 것이 좋다. 

 - 그래도 기본은 알고 가야 하니까... 코드를 보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React from "react";
import ReactDOM from "react-dom";
 
class Secret extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name"top secret!"
    };
    this.onButtonClick = this.onButtonClick.bind(this);
  }
  onButtonClick() {
    this.setState(() => ({
      name"Younghoi Kim"
    }));
  }
  render() {
    return (
      <div>
        <h1>My name is {this.state.name}</h1>
        <button onClick={this.onButtonClick}>reveal the secret</button>
      </div>
    );
  }
}
 
ReactDOM.render(<Secret />, document.getElementById("app"));
 



※ 주의: 리액트 컴포넌트 내에서 this.state를 직접 갱신하는 일은 절대로 없어야 한다. 

 - 개발자가 직접 갱신한 상태를 리액트가 제대로 처리하지 못하기 때문에 좋지 않다. 

 - 컴포넌트 내에서는 this.state를 속성처럼 불변객체로 취급해야 한다. 


setState 메소드는 updater 함수가 리턴한 객체를 얕은 복사 기법을 이용해 현재의 상태를 병합한다. 

*얕은 복사? 지정된 값을 한 객체로부터 다른 객체로 복사하는 방법
 - 객체의 경우 = 를 이용하여 복사하면 '참조 복사' 가 된다.  
 - 때문에 복사 후에 원복 객체의 값을 변경하면 복사된 객체의 값에도 영향이 있다. 
 - 독립적으로 동작하도록 깊은 복사를 하려면 아래와 같이 해야 한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const clone = function(obj) {
  var cloneObj = {};
  for(var i in obj) {
    cloneObj[i] = obj[i];
  }
  return cloneObj;
}
 
let orgObj = {
  name'Younghoi Kim',
  age: 20
}
let copiedObj = clone(orgObj);
orgObj.age = 30;
console.log(orgObj);
console.log(copiedObj);


*깊은 복사? 새로운 객체를 만들어 기존 객체를 교체하는 방법 
 - 기본 자료형(숫자, 문자열, boolean)의 값을 복사할 때 값을 완전히 복사한다. 
 - 때문에 완전히 독립적이며 복사한 변수와 복사대상 변수는 서로 영향이 없다. 


setState 메서드를 이용한 얕은 복사를 오해하여 발생할 수 있는 문제에 대해서 살펴보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React from "react";
import ReactDOM from "react-dom";
 
class ShallowMerge extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      user: {
        name"Younghoi Kim",
        colors: { favorite: "" }
      }
    };
    this.onButtonClick = this.onButtonClick.bind(this);
  }
  onButtonClick() {
    this.setState({
      user: {
        colors: { favorite: "black" }
      }
    });
  }
  render() {
    return (
      <div>
        <h1>
          My favorite color is {this.state.user.colors.favorite} and my name is{" "}
          {this.state.user.name}
        </h1>
        <button onClick={this.onButtonClick}>show the color!</button>
      </div>
    );
  }
}
 
ReactDOM.render(<ShallowMerge />document.getElementById("app"));
 


위 애플리케이션은 My favorite color is and my name is Younghoi Kim 이라는 결과를 보이고 

버튼을 클릭하면 My favorite color is black and my name is Younghoi Kim 이라는 결과가 나오길 희망한다. 

하지만 결과는 My favorite color is black and my name is 라고 나오게 된다. 

최초 상태의 user 키 안에 중첩된 name 속성은 새 상태에는 존재하지 않기 때문에 빈 값으로 덮어써지게 되는 것이다. 


다음글: 2019/03/15 - [IT/React] - React - 상태(불변 상태 - props)


728x90
반응형
LIST