state

Posted by yunki kim on June 20, 2021

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를 바꿀 수 있다.