본문 바로가기
Web/React

React : 구구단 예시 (State, setState)

by Jun_N 2020. 7. 27.

구구단 게임 만들기

State 사용하는곳 찾기

이 구구단 게임에서 입력을 누를때 바뀌는곳은 첫줄의 숫자들, 입력창, 결과창(땡,정답) 총 3곳이 바뀌게 된다.

따라서 State는 3개이다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <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/babel.min.js"></script>

    <meta charset="UTF-8" />
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      class GuGuDan extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            first: Math.ceil(Math.random() * 9),
            second: Math.ceil(Math.random() * 9),
            value: "",
            result: "",
          };
        }

        onSubmit = (e) => {
          e.preventDefault();
          if (
            parseInt(this.state.value) ===
            this.state.first * this.state.second
          ) {
            this.setState({
              result: "정답!!",
              first: Math.ceil(Math.random() * 9),
              second: Math.ceil(Math.random() * 9),
              value: "",
            });
          } else {
            this.setState({
              result: `땡!! 정답은 ${this.state.first * this.state.second}`,
              value: "",
            });
          }
        };

        onChange = (e) => {
          this.setState({ value: e.target.value });
        };

        render() {
          return (
            <div>
              <div>
                {this.state.first} 곱하기 {this.state.second}는?
              </div>
              <form onSubmit={this.onSubmit}>
                <input
                  type="number"
                  value={this.state.value}
                  onChange={this.onChange}
                />
                <button>입력! </button>
              </form>
              <div>{this.state.result}</div>
            </div>
          );
        }
      }
    </script>

    <script type="text/babel">
      ReactDOM.render(<GuGuDan />, document.querySelector("#root")); //LikeButton을 root안에다가 그리겠다.
    </script>
  </body>
</html>

 

setState를 통해 상태가 변경시킬 수 있다.

onChange를 통해서 입력을 받은 값(상태)을 value에 저장시킬 수 있고

onSubmit을 통해서 정답을 맞출때, 맞추지 못할때에 따라서 state를 변화시켜서 화면에 출력시킨다.

 

*참고

render()에서 <div>는 의미없이 한번을 묶어주는 역할을 하는데 이를 <>로 빈 칸으로 만들어도 된다.

 


setState에서 현재 값 구분해주기.

this.setState((Current) => {
              return {
                result: "정답!! " + Current.value,
                first: Math.ceil(Math.random() * 9),
                second: Math.ceil(Math.random() * 9),
                value: "",
              };
            });

setState에서 this.state.value를 사용할때 이게 현재 기준 값인지 헷갈릴때가 있다. 특히 count를 할때 여러개를 동시에 사용하면 비동기 방식이기 때문에 문제가 된다.

이를 해결하기 위해서는 setState에 함수를 추가하여 return 해준다.

보이는 것처럼 Current 함수에 return을 통해서 현재 상태의 value를 보여주는 것으로 표시할 수 있다.

 


ref 

ref는 input form에서 제출을 눌렀을때 화면이 바껴도 마우스 커서가 입력창에 가있는걸 하기 위해 사용한다.

<input
                  ref={(c) => {
                    this.input = c;
                  }} // input에 focus(커서) 효과 주기
           
                />

 여기서 c는 임의에 이름이다. input일때, this.input이면 된다.

이렇게 정의한 다음에

else {
            this.setState({
              result: `땡!! 정답은 ${this.state.first * this.state.second}`,
              value: "",
            });
            this.input.focus();
          }
        };

위에 if구문 끝, 혹은 else구문 끝에 this.input.focus()를 추가하면 화면이 바뀔때 입력창에 마우스 커서가 focus되는 것을 확인할 수 있다. 

 

참고로 setState가 될때마다 render가 한번 실행된다.

나중에 render가 많이 일어나면 웹사이트 속도가 느려져서 setState를 사용할때 주의해야 한다.

함수를 render에서 빼서 따로 선언 해주는 이유도 그것이다.

 

최종 code

<!DOCTYPE html>
<html lang="ko">
  <head>
    <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/babel.min.js"></script>

    <meta charset="UTF-8" />
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      class GuGuDan extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            first: Math.ceil(Math.random() * 9),
            second: Math.ceil(Math.random() * 9),
            value: "",
            result: "",
          };
        }

        onSubmit = (e) => {
          e.preventDefault();
          if (
            parseInt(this.state.value) ===
            this.state.first * this.state.second
          ) {
            this.setState((Current) => {
              return {
                result: "정답!! " + Current.value,
                first: Math.ceil(Math.random() * 9),
                second: Math.ceil(Math.random() * 9),
                value: "",
              };
            });
            this.input.focus();
          } else {
            this.setState({
              result: `땡!! 정답은 ${this.state.first * this.state.second}`,
              value: "",
            });
            this.input.focus();
          }
        };

        onChange = (e) => {
          this.setState({ value: e.target.value });
        };

        onRefInput = (c) => {
          this.input = c;
        };

        render() {
          return (
            <>
              <div>
                {this.state.first} 곱하기 {this.state.second}는?
              </div>
              <form onSubmit={this.onSubmit}>
                <input
                  ref={this.onRefInput} // input에 focus(커서) 효과 주기
                  type="number"
                  value={this.state.value}
                  onChange={this.onChange}
                />
                <button>입력! </button>
              </form>
              <div>{this.state.result}</div>
            </>
          );
        }
      }
    </script>

    <script type="text/babel">
      ReactDOM.render(<GuGuDan />, document.querySelector("#root")); //LikeButton을 root안에다가 그리겠다.
    </script>
  </body>
</html>

 

*참고 링크

https://www.youtube.com/watch?v=nsS5mbyDDBw&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn&index=10