[React 교과서] 4장 React 컴포넌트의 객체 상태

리엑트 교과서를 정리한 내용입니다.

리엑트에서 가장 중요한 부분이다.

4.1 React컴포넌트의 상태란?

React의 상태는 컴포넌트의 변경 가능한 데이터 저장소이다.
컴포넌트를 속성과 상태가 있는 함수라고 생각하면 함수의 결과가 UI표현(뷰)이다.
속성과 상태는 모두 뷰를 갱신하기 위해 사용하지만 목적이 다름.

  • 상태:
    상태는 이름을 활용하여 접근함. this.state 객체속성 ex) this.state.inputFileValue
    뷰의 랜더링이 갱신될 때 동적 정보를 출력하기 위해 사용됨.
    관련된 부분만 갱신됨.

아래 안티 패턴 예시
상태 외의 다른 값을 변경해도 뷰를 갱신할 수 없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let inputValue ='Texas'
class Autocomplete extends React.Component {
updateValues(){ //--사용자 입력에 의해 실행됨
this.props.inputValue = 'California'
inputValue ='California'
this.inputValue='California'

}
render(){
return(
<div>
{this.props.inputValue}
{inputValue}
{this.inputValue}
</div>
)
}
}

속성은 부모 컴포넌트에서 새로운 값을 전달하면 뷰를 갱신하여 현재 다루는 자식 컴포넌트의 새로운 인스턴스를 생성함.
해당 자식 컴포넌트의 컨텍스트내에서 this.props.inputValue=’California’로 변경해도 소용이 없음!

4.2 상태 객체 다루기

4.2.1 상태 객체에 접근하기

맴버변수로 this 를 통해 접근 가능. this.state.name와 같은 방식으로 접근.
render()에서 this.state를 랜더링 할 수 있음. ex) {this.state.inputFieldValue}

  • 현재 시간 출력하는 시계 구현하기
    • 폴더 구조
      /clock
      index  
      
      /jsx
      script.jsx  
      clock.jsx  
      
      /js
      script.js  
      clock.js  
      react.js  
      react-dom.js  
      
1
2
3
4
5
6
7
8
9
10
11

class Clock extends React.Component{
render(){
return <div>{this.state.currentTime}</div>
}
}

ReactDOM.render(
<Clock/>
document.getElementById('content')
)

위와 같이 하면 ‘currentTime’ 값이 null이라는 오류가 발생한다.
속성과 달리 상태는 부모 객체에서 설정하는것이 아니고 render()안에서 setState를 실행 할 수도 없다.

4.2.2 초기 상태 설정하기

초기 상태를 설정하려면 React.Component를 사용하는 ES6클래스의 생성자에서 this.state를 선언함. 반드시 super()에 속성을 전달하여 실행한다.

1
2
3
4
5
6
7
8
9
class MyFancyComponent extends React.Component{
constructor(props){
super(props)
this.state = {...}
}
render(){
...
}
}

초기 상태를 설정하면서 다른 로직도 추가 가능.
ex) new Date()를 사용하여 currentTime 값을 설정함. toLocaleString()을 사용하면 상용자 위치에 맞는 적절한 날짜시간 형식을 보여줄 수 있음.

1
2
3
4
5
6
7
class Clock extends React.Component{
constructor(props){
super(props)
this.state={currentTime: (new DAte()).toLocaleString('en')}
}
...
}

초기 상태 주의사항

  • this.state는 반드시 객체여야함.
  • 생성자 메서드의 이름은 반드시 constructor로 함.
  • 부며 클래스가 있는 클래스에서 construtcor()매서드를 생성하면 항상 super()를 호출함.
  • 상속으로 클래스를 구현하면 constructor()매서드를 따로 작성하지 않으면 super()를 호출한것으로 가정함.
  • constructor()메서드 내에서 한번만 this.state로 직접 상태를 선언하고 그 외 부분에서는 this.stat=…로 직접 상태 선언하지 않는다.

4.2.3 상태 갱신하기

클래스 매서드인 this.setState(data, callback)를 사용하면 상태 변경 가능.
data를 현재 상태에 병합하고 render()을 호출, 이후 callback함수 실행됨.
setState()가 비동기로 작동함.

시계를 시작하려면 setInterval()을 한번 호출해야함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Clock extends React.Component{
counstructor(props){
super(props)
this.lauchClock()
this.state ={
currentTime: (new DAte()).toLocaleString('en')
}
}
launchClock(){
setInterval(()=> {
console.log('Updating time...')
this.setState({
currentTime: (new Date()).toLocaleString('en')
})
}, 1000)
}
render() {
console.log('Rendering Clock...')
return <div>{this.state.currentTime}</div>
}
}

setState()로 상태를 교체할때 상태 항목이 여러개 있으면 명시해준것만 바뀌고 나머진 값이 그대로임.
setState()가 render()를 실행시킴.

4.3 상태 객체와 속성

상태 객체와 속성은 모두 클래스의 맴버이며 각각 this.state와 this.props를 말함.

  • 상태 객체 vs 속성 객체
    • 상태 객체는 변경가능, 속성 객체는 변경 불가능.
    • 상태는 해당 컴포넌트 자체에서 정의, 속성은 부모 컴포넌트에서 전달(부모컴포넌트에서만 값을 변경 가능함).
    • 상태는 컴포넌트에서 설정되고 갱신, 속성은 뷰 생성시에 정해지고 변경안됨.

4.4 상태비저장 컴포넌트

  • 상태비저장 컴포넌트는 상태 객체가 없고 이벤트 또는 메서드를 갖지 않음.
  • 상태비저장 컴포넌트의 목적은 뷰를 랜더링 하는것 뿐임.
  • 속성을 전달받아 처리.
  • 예측하기 편해서 이해, 유지보수, 디버깅이 편함.
    => 상태비저장컴포넌트 많이 사용하고 상태저장컴포넌트는 적게 사용하는게 바람직함.

아래는 상태비저장 컴포넌트 예제

1
2
3
4
5
class HelloWorld extends React.Component{
render(){
return <h1{...this.props}> Hello{ this.props.frameworkName} world!!!</h1>
}
}

상태가 필요하지 않으면 함수로 선언하면됨.

1
2
3
4
5
6
7
8
9
10
functipn Link(props){
return <a href ={props.href} target="_blank" className="btn btn-primary">
{props.text}</a>
}

ReactDOM.render(
<Link text ='Buy React Quickly'
href ='https://www.manning.com/books/react-quickly' />,
document.getElementById('content')
)

1
2
3
4
5
6
7
8
9
const Link = (props)=>{
return (
<href={props.href}
target ="_blank"
className="btn btn-primary" >
{props.text}
</a>
)
}

상태비저장 컴포넌트는 상태를 가질 수 없지만 propTypes와 defaultProps를 프로퍼티로 가질 수 있다.

1
2
3
4
5
6
7
8
9
10
function Link (props){
return <a href = {props.href}
target="_blank"
className="btn btn-primary">
{props.text}
</a>
}

Link.propTypes={...}
Link.defaultProps={...}

4.5 상태비저장 컴포넌트와 상태저장 컴포넌트의 비교

HTML 렌더링을 처리하는것으로 충분한 경우 상태비저장 컴포포넌트가 더 선언적이고 작동이 잘됨.

  • 상태를 사용해야 하는 경우

    • UI 상태, 상호작용, 서버에서 데이터 불러오는것 등 을 관리하려면 상태저장 컴포넌트를 활용한다.
  • 아날로그와 디지털 방식으로 노출하는 시계

    • 프로젝트 구조
      /clock-analog-digital
      /jsx
      analog-display.jsx  
      clock.jsx  
      digital-display.jsx  
      script.jsx  
      
      /js
      analog-display.js  
      clock.js  
      digital-display.js  
      script.js  
      react.js  
      react-dom.js  
      
      /
      index.html
1
2
3
4
5
6
7
8
...
render() {
console.log('Rendering...')
return <div>
<AnalogDisplay time={this.state.currentTime}/>
<DigitalDisplay time={this.state.currentTime}/>
</div>
}
1
2
3
const DigitalDisplay = function(props){
return <div>{props.time}</div>
}
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
const AnalogDisplay = function (props) {
let date = new Date(props.time);
let dialStyle = {
position: 'relative',
top: 0,
left: 0,
width: 200,
height: 200,
borderRadius: 20000,
borderStyle: 'solid',
borderColor: 'black'
};
let secondHandStyle = {
position: 'relative',
top: 100,
left: 100,
border: '1px solid red',
width: '40%',
height: 1,
transform: 'rotate(' + (date.getSeconds() / 60 * 360 - 90).toString() + 'deg)',
transformOrigin: '0% 0%',
backgroundColor: 'red'
};
let minuteHandStyle = {
position: 'relative',
top: 100,
left: 100,
border: '1px solid grey',
width: '40%',
height: 3,
transform: 'rotate(' + (date.getMinutes() / 60 * 360 - 90).toString() + 'deg)',
transformOrigin: '0% 0%',
backgroundColor: 'grey'
};
let hourHandStyle = {
position: 'relative',
top: 92,
left: 106,
border: '1px solid grey',
width: '20%',
height: 7,
transform: 'rotate(' + (date.getHours() / 12 * 360 - 90).toString() + 'deg)',
transformOrigin: '0% 0%',
backgroundColor: 'grey'
};
return React.createElement(
'div',
null,
React.createElement(
'div',
{ style: dialStyle },
React.createElement('div', { style: secondHandStyle }),
React.createElement('div', { style: minuteHandStyle }),
React.createElement('div', { style: hourHandStyle })
)
);
};

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×