본문 바로가기
dev/React

[React] 상태 다루기

by dev_Step 2022. 11. 30.

 - 지금까지의 컴포넌트는 무상태 컴포넌트 였다. 부모로 부터 받은 속성은 있으나, 실행될 때 그 속성에 관한 어떤 변화도 일으키지 않았다.

 -  하지만 사용자와의 상호작용 결과로 컴포넌트의 어떤 부분은 변경되거나, 서버로부터 데이터를 가지고 오거나, 그밖에 무수히 많은 일들이 일어날수 있다. 

 

즉 .. 우리에게 필요한것은

 >> 속성의 수준을 넘어 컴포넌트에 데이터를 저장하는 또 다른 방법이다.

 >. 이는 변경되는 데이터를 저장해야 한다는 의미이다. 그 데이터를 바로 상태(state) 라고 한다.

 

 

1. 상태 사용하기

 -- 간단한 앱을 만들어 실습해보도록 하자 (번개친 횟숫 카운트하기)

 >> LightningCounterDisplay 라는 컴포넌트는  

render() 에서 스타일 객체를 만들어 <div> 태그에 스타일을 지정하고 <LightningCounter/>를 호출 하고 있다.

 

>> LightningCounter 에서는 단지  <h1>Hello</h1>을 리턴할 뿐이다.

 

ReactDOM.render() 함수에서는  LightningCounterDisplay 컴포넌트를 DOM 안의 container 엘리먼트에 넣고 있다

최종 결과는 LightningCounterDisplay 와 LightningCounter 컴포넌트 그리고 ReactDOM.render 메소드가 조합된 마크업이다.

 

2. counter 키기

 >> 이제 Counter를 한번 켜보도록 하자 (LightningCounter 부분을 다룰예정) 

 1) 초기 상태 값 설정

   strikes 변수를 설정하는데 이 변수는 컴포넌트 상태의 일부분 이다. 따라서 state 객체를 만들고 그 속성으로 strikes 변수를 사용함으로써 컴포넌트가 생성될 때 그 모든 준비가 되게 끔 진행할 것이다.

 2) 타이머 가동과 상태 설정

  -  이제 타이머를 시작 시키고 strikes 속성 값을 증가 시켜야 할 차례이다. setInterval 함수를 사용해 strikes 속성을 매초마다 100씩 증가 시킬것이다. 이는 컴포넌트가 렌더링된 직후에 실행되는 componentDidMount() 메서드를 이용하면된다.

  -  componentDidMount() 메서드는 렌더링 된 후 한번 호출 되므로, 그 안에 매초마다 timeTick() 함수를 호출하는 setInterval() 를 추가해 줬다.

  - 또한 timerTick() 를 정의해 주었다.

  - 컴포넌트에 timerTrick 함수는 추가되었지만, 그 콘텐츠에 컴포넌트의 컨텍스트가 유지되지는 않는다

  - 현재 상황에서는 this.setState는 typeError를 리턴할것이다.

  - 일단 지금은 timerTick 함수를 컴포넌트에 명시적으로 바인딩 시키는 방법을 사용하자.

  - 생성자에서 timerTick 을 bind 시켜주었다.

 

그러면 이제 앱을 테스트 해보도록 하자

마지막으로 정리를 해보자면

ReactDOM.render() 를 통해서 <LightningCounterDisplay / > 컴포넌트가 #container 의 div안으로 들어 가게 되고

LightningCounterDisplay 컴포넌트에서는 <LightningCOunter/> 컴포넌트를 <div style={divStyle}> 태그로 둘러 싸서 리턴해 준다. LightningCounter에서는  컴포넌트가 렌더링 되면 생성자에 의해서 state 객체가 생성되고 strikes = 0으로 초기화 시켜준다. 그 후 렌더링 후 실행되는 componentDidMount() 함수가 호출되면서 내부에 있던 setInterval() 함수를 통해 1초마다 timerTick() 함수를 호출해 준다. 이때 생성자에서 timerTick() 함수를 사용하기 위해서 bind 해주는 모습을 볼수 있었다. 그후 {this.state.strikes} 를 리턴해주면서 1초마다 100씩 증가하는 것을 확인  할 수 있다.

-- 이때 setState({}) 함수를 통해 state 객체에 어떤 내용이 변경될때마다 컴포넌트의 render 메소드가 자동으로 호출된다.이는 연관된 다른 모든 컴포넌트들의 render함수를 연쇄적으로 호출한다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <style>

    </style>
</head>
<body>

    <div id="container"></div>
    <script type="text/babel">

        class LightningCounter extends React.Component{

            constructor(props){
                super(props);
                
                this.state = {
                    strikes : 0
                }; 

                this.timerTick = this.timerTick.bind(this);
            }

            timerTick(){
                this.setState({
                    strikes : this.state.strikes + 100
                });
            }

            componentDidMount(){
                setInterval(this.timerTick, 1000);
            }

            render(){

                var counterStyle = {
                    color : "#66ffff",
                    fontSize : 50
                }

                var count = this.state.strikes.toLocaleString();

                return(
                    <h1>{this.state.strikes}</h1>
                )
            }
        }

        class LightningCounterDisplay extends React.Component{
            
            render(){

                var commonStyle ={
                    margin : 0,
                    padding : 0
                }
                var divStyle = {
                    width : 250,
                    textAlign : "center",
                    backgroundColor : "#020202",
                    padding : 40,
                    fontFamilty : "sans-serif",
                    color : "#999",
                    borderRadius : 10
                }
                var textStyles = {
                    emphasis : {
                        fontSize : 38,
                        ...commonStyle
                    },
                    smallEmphasis : {
                        ...commonStyle
                    },
                    small : {
                        fontSize : 17,
                        opacity : 0.5,
                        ...commonStyle
                    }
                };
                return(
                    <div style={divStyle}>
                        <LightningCounter/>
                        <h2 style={textStyles.smallEmphasis}>LIGHTNING STRIKES</h2>
                        <h2 style={textStyles.emphasis}>WORLDWIDE</h2>
                        <p style={textStyles.small}>(since you loaded this example)</p>
                    </div>
                )
            }
        }

        ReactDOM.render(
            <LightningCounterDisplay/>
            , document.querySelector("#container")
        );
    </script>
</body>
</html>

'dev > React' 카테고리의 다른 글

[React] 이벤트  (0) 2022.11.30
[React] 데이터에서 UI로  (0) 2022.11.30
[REACT] JSX 특징  (0) 2022.11.30
[React] 속성 전달  (0) 2022.11.29
[React] 복잡한 컴포넌트 제작  (0) 2022.11.29