state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다. props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이고 컴포넌트 자신은 해당 props를 읽기 전용으로 만 사용할 수 있다. props의 값을 바꿀려면 부모 컴포넌트에서 바꾸어야 한다.
리엑트에는 (1). 클래스형 컴포넌트가 지니고 있는 state, (2).함수형 컴포넌트가 지니고 있는 useState를 통해 사용하는 state 총 두개가 있다.
Class형 컴포넌트
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
|
import React, {Component} from 'react';
class Counter extends Component {
//생성자에서 state 설정을 해줘야 한다.
constructor(props){
super(props);//클래스형 컴포넌트는 반드시 Component가 지닌 생성자를 호출해야 한다
this.state = {//state는 반드시 객체 형식이어야 한다.
number: 0,
fixed_state: 0,
};
}
render() {
const {number} = this.state;//state는 반드시 this.state로 조회한다
return (
<div>
<h1>{number}</h1>
<h2>Fixed number: {fixed_number}</h2>
<button
{/*arrow function을 사용해야 this.setState가 제대로 동작한다*/}
onClick = {() => {
//setState로 새로운 값을 넣을 수 있다
//바뀌길 원하지 않는 값이 있다면 set을 하지 않으면 된다.
this.setState({number: number + 1});
}}
>
+1
</button>
</div>
);
}
}
export default Counter;
//버튼 한번 클릭 후 결과:
//number: 1
//fixed_number: 0
//생성자를 사용해 state를 설정하고 싶지 않다면
//state = {..}처럼 사용하면 된다
|
cs |
** this.setstate**
this.setstate()는 비동기적으로 업데이트 된다. 그때문에 위 코드에 click이벤트에서 콜백을 다음과 같이 바꾼다면 원하는 값이 나오지 않는다. 이는 비동기 이므로 state값이 바로 바뀌지 않기 때문이다.
onClick={() => {
this.setState({number: number + 1});
this.setState({number: this.state.number + 1});
}}
//원하는 결과: number + 2
//실제 출력: number + 1
이를 해결하기 위해서는 함수를 인자로 넣어주면 된다.
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
|
import React, {Component} from 'react';
class MyClassComponent extends Component {
state = {
number: 0,
fixed_number: 0,
};
render() {
const {number, fixed_number} = this.state;
return (
<div>
<h1>{number}</h1>
<h2>Fixed number: {fixed_number}</h2>
<button
onClick = {() => {
//prev_state는 기존 상태
//props는 현재 지니고 있는 props
this.setState((prev_state, props) => {
return {
number: prev_state.number + 1
};
});
this.setState(prev_state => ({
number: prev_state.number + 1
}));
}}
>
+1
</button>
</div>
);
}
}
export default MyClassComponent;
|
cs |
this.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
|
import React, {Component} from 'react';
class MyClassComponent extends Component {
state = {
number: 0,
fixed_number: 0,
};
render() {
const {number, fixed_number} = this.state;
return (
<div>
<h1>{number}</h1>
<h2>Fixed number: {fixed_number}</h2>
<button
//callabck 또는 await, async사용 가능
onClick = {() => {
this.setState({
number: number + 1
}, () => {
console.log('setState: ');
console.log(this.state);
});
}}
>
+1
</button>
</div>
);
}
}
export default MyClassComponent;
|
cs |
함수형 컴포넌트에서 useState 사용
리엑트 V16.8이전에는 함수형 컴포넌트에서 state를 사용할 수 없었다. 하지만 그 이후부터는 useState를 통해 함수형 컴포넌트에서도 state를 사용할 수 있게 되었다. 이 과정에서 Hooks이 사용되는데 이에 대한 내용은 나중에 설명하기로 하자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import React, {useState} from 'react';
const Say = () => {
//useState함수 인자에는 상태의 초기값을 넣어 준다.
//이 초기값은 클래스형 컴포넌트와는 달리 값의 형태에 구애받지 않는다.
//useState()를 호출하면 배열이 반환되며 첫번째 원소는 현재 상태, 두번째는 상태에 대한 setter이다.
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage('Hello');
const onClickLeave = () => setMessage('Bye');
return (
<div>
<button onClick={onClickEnter}>enter</button>
<button onClick={onClickLeave}>leave</button>
<h1>{message}</h1>
</div>
);
};
export default Say;
|
cs |
한 컴포넌트에서 useState 여러번 사용하기
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, {useState} from 'react';
const Say = () => {
const [message, setMessage] = useState('new');
const onClickEnter = () => setMessage('Hello');
const onClickLeave = () => setMessage('Bye');
const [color, setColor] = useState('black');
return (
<div>
<button onClick={onClickEnter}>enter</button>
<button onClick={onClickLeave}>leave</button>
<h1 style=>{message}</h1>
<button style= onClick={() => setColor('red')}>
red
</button>
<button style= onClick={() => setColor('green')}>
green
</button>
<button style= onClick={() => setColor('blue')}>
blue
</button>
</div>
);
};
export default Say;
|
cs |
State를 사용할때의 주의 사항
컴포넌트 유형에 따라 setState 또는 useState만을 사용해 값을 바꾸어야 한다. 또 한 객체, 배열의 값을 바꿀때는 사본을 만들어서 사본의 값을 변경한 후 상태를 없데이트 해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//객체
const obj = {a:1, b:2, c:3};
const nextObj = {...obj, b:2};//사본을 만들어 b값만 덮어 쓴다
//배열
const array = {
{id:1, value:ture},
{id:2, value:true},
{id:3, value:false}
};
let next_array = array.concat({id:4});
next_array.filter(item => item.id !== 2);
//id가 1인 항목의 value를 1로 설정
next_array.map(item => (item.id) === 1 ? {...item, value: false} : item));
|
cs |
props와 state
props는 부모 컴포넌트가 설정하고, state는 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트할 수 있다. props가 반드시 고정적이다 라는 법은 없다. 부모 컴포넌트의 state를 props로 자식에게 전달하도 자식 컴포넌트에서 특정 이벤트 발생 시 부모 컴포넌트의 메서드를 호출하면 props를 바꿀 수 있다.