[2022.07.16] (복습) 리액트로 숫자야구 게임 만들기 - 클래스형 컴포넌트

REASON·2022년 7월 16일
0

복습

목록 보기
6/12

어제 제로초님 영상보면서 배운 숫자야구 게임을 복습겸 혼자 만들어 보았다.

나름 귀엽게 이모지도 넣고 css 애니메이션도 줬다.. ㅎㅎ

숫자를 입력후 확인 버튼을 누르면 현재 문제와 입력값의 자리와 숫자가 일치하는 경우 스트라이크가 1 증가하고 자리는 일치하지 않지만 숫자만 일치하면 볼이 1 증가하는 게임이다.

정답을 맞추면 홈런! alert 창이 뜨고 새 게임이 바로 시작된다.

10회 도전에 실패하면 3초뒤 새로운 게임으로 재시작된다.
생각해보니 도전 횟수도 적어줬어야 했는데 깜박했다..ㅋㅋㅋ

작성한 전체 코드 (클래스형 컴포넌트)

import React, { Component } from 'react';
import style from './styles/style.css';

function newGame() {
  const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  const array = [];

  for (let i = 0; i < 4; i++) {
    array.push(candidate.splice(Math.floor(Math.random() * 9 - i), 1)[0]);
  }
  return array;
}

class NumberBaseball2 extends Component {
  state = {
    userInputValue: '',
    quiz: newGame(),
    result: [],
  };

  timer = () => {
    setTimeout(() => {
      this.setState({
        userInputValue: '',
        quiz: newGame(),
        result: [],
      });
    }, 3000);
  };

  onSubmit = (e) => {
    e.preventDefault();

    const currentQuiz = [...this.state.quiz];
    let currentResult = '';

    // 현재 문제 정답을 string으로 타입 변환 뒤 + 연산하여 문자 이어붙이기
    currentQuiz.forEach((v) => {
      currentResult += v.toString();
    });

    if (this.state.result.length >= 10) {
      this.timer();
      this.setState({
        result: [...this.state.result, { comment: `10회 도전했으나 실패하여 3초 후 새게임을 시작합니다.` }],
        quiz: newGame(),
        userInputValue: '',
      });
      alert('10회 도전했으나 실패하여 3초 뒤 새게임을 시작합니다.');
    } else {
      if (currentResult === this.state.userInputValue) {
        this.setState({
          result: [],
          quiz: newGame(),
          userInputValue: '',
        });

        alert('홈런! 새 게임을 시작합니다.');
      } else {
        let strike = 0;
        let ball = 0;

        for (let i = 0; i < 4; i++) {
          if (currentResult[i] === this.state.userInputValue[i]) {
            strike += 1;
          } else if (this.state.userInputValue.includes(currentResult[i])) {
            ball += 1;
          }
        }

        this.setState({
          result: [...this.state.result, { answer: this.state.userInputValue, comment: `${strike} 스트라이크, ${ball} 볼 입니다!` }],
          userInputValue: '',
        });
      }
    }
  };

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

  render() {
    return (
      <div className="bg">
        <h2 className="title">
          <span className="baseball-icon"></span> 숫자 야구 게임 <span className="baseball-icon"></span>
        </h2>
        <p className="sub-text">1 ~ 94가지 숫자를 입력하세요.</p>
        <form className="game-container" onSubmit={this.onSubmit}>
          <input onChange={this.onChange} value={this.state.userInputValue} className="input-box" type="number" />
          <button className="btn">확인</button>
        </form>
        <ul className="result-container">
          {this.state.result.map((v, i) => {
            return (
              <li key={`${i}번째 도전`}>
                {v.answer}{v.comment}
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default NumberBaseball2;

추가해볼 것

  1. 사용자가 입력한 숫자가 4개를 초과하거나 4개 미만일 때, 공백 입력한 경우도 처리하기
  2. 게임 재시작 타이머 넣기
  3. 도전 횟수 추가하기 (까먹었음)
  4. 10회 이상 실패했을 때 이전 게임 정답 보여주기
  5. 추가할 사항은 아니지만..! 주석 넣기, 변수, 함수 이름 잘 짓기도 좀 더 신경쓰기

사용자가 10번 동안 맞추지 못하면 새로운 게임으로 재시작되는데 이때 재시작 타이머(3 -> 2 -> 1) 카운트되는 것을 화면에 보여주도록 하고 싶었는데 setInterval 함수를 리액트에 어떻게 적용해야 될지 몰라서 일단은 보류했다..ㅠㅠ

아쉬운대로 setTimeout으로 3초후 게임을 재시작하도록 했는데 나중에 다시 만들어볼때는 이 기능도 넣어봐야겠다.

react hooks로 다시 만들어볼 것이기 때문에 그때 부족한 부분은 추가해 넣어 보도록 해야겠다. ㅎㅎ

강의 보면서 따라 만들면 에러가 날 확률이 거의 없다보니 내가 무엇을 모르는지 정확히 모르고 넘어가는 경우가 생기는 것 같아서 배운 내용을 혼자서 실습해보면서 모르는 건 구글링해서 다시 찾아보고 헷갈리던 개념은 다시 잡을 수 있어서 좋은 것 같다. 제로초님의 숫자야구 게임 코드 보면서 이 코드는 왜 이렇게 동작할까? 싶었던 것도 차근차근 살펴보니 이해가 되는 부분도 있었다.

이번에 숫자 야구 게임 다시 만들어보면서 스트라이크와 볼이 제대로 카운트 되는지 궁금해서 확인 버튼을 누르면 현재 state 값을 콘솔에 찍어보도록 했는데
state를 콘솔에 찍어서 나타난 시점의 데이터가 실제 데이터보다 한차례 늦는 것 같다...
이거 때문에 왜 setState를 사용했는데 result 배열에 아무것도 없지..? 하고.. 코드를 잘못 짠 줄 알고 몇시간이나 허탕을 쳤다.ㅠㅠ

넘나 어려운 리액트쨩,, 😓

고쳐야 하는 부분

클래스형 컴포넌트에서 이전 state값을 사용하여 현재 값을 만들때는 함수형 setState를 사용해야 한다고 한다..!

this.setState({
  result: [...this.state.result, { comment: `10회 도전했으나 실패하여 3초 후 새게임을 시작합니다.` }],
  quiz: newGame(),
  userInputValue: '',
});

이 부분을 아래 코드처럼 수정해야 된다

this.setState((prevState)=>{
	return {
    	// 이 안에 담아야함
    }
})

그래야 setState를 연달아 사용할 때 문제가 생기지 않는다고 한다. 옛날 스테이트로 현재 스테이트 만들 때는 함수형 setState 사용하기!

0개의 댓글