가위바위보 게임 만들기

dana·2021년 12월 9일
1

토이프로젝트

목록 보기
5/17

이 블로그를 참고해 토이프로젝트를 진행했습니다.

가위바위보 게임

빠르게 가위바위보 패를 내는 컴퓨터에 유저가 가위 바위 보 버튼을 눌러 승패를 가르는 게임입니다.

게임 기능

  • 컴퓨터 (gamer)
    - 순서대로 빠르게 컴퓨터의 가위바위보 값이 변경되어 출력
  • 유저 (user)
    - 승패를 결정할 가위, 바위, 보 버튼 구현
    • 버튼 클릭시 컴퓨터의 패가 확정되며, 유저의 패와 비교해 승패 결정 후, 알람 구현
  • 점수
    - 컴퓨터가 이긴 경우 컴퓨터에게, 유저가 이긴 경우 유저에게 점수 1점씩 변경
    • 점수 초기화 버튼 및 동작 구현

게임 동작 예시

실행 방법

개발 환경

  • Mac OS 사용
  • VSC Version: 1.62.3
  • yarn 1.22.17
  • react 17.0.2

사용 기술

HTML / CSS / JavaScript / React

실행 방법

게임 실행하기
모바일 환경에서는 오류가 발생할 수 있습니다.

개발하면서 느낀점

오류 사항

class 컴포넌트 this binding

class 컴포넌트 사용을 다들 말리길래 왜일까 했는데, 이번 프로젝트에 App.js를 클래스 컴포넌트로 사용하면서 확실히 느꼈다. 함수를 내부에 선언해서 사용하기 위해선 this바인딩을 해줘야하는데 이렇게 사용하다보니 변수가 this로 범벅되어 코드 가독성이 떨어진다는 느낌을 받았다.

처음 function 안에서 state값을 받아올 때, this.state.value의 값이 받아와지지 않는 오류가 있었다. 이 때 함수에 this바인딩을 해주지 않아 생긴 문제였고, 이 오류를 해결하기 위해 constructor에서 this.func = this.func.bind(this)를 작성해 주어야 했다.

왜 여기서 바인드를 해주어야하나 살펴보니 자바스크립트에서 클래스 내의 function들은 바인딩이 되어있지 않다. 그래서 onClick={this.funcName} 과 같이 () 없이 이벤트 함수를 바로 입력해 주는 경우 this의 값이 undefined로 설정되어 오류가 나게 된다.

내가 짠 코드에서도 setState가 콜백함수로 작성되어 부모 (여기서는 window)의 값을 받아오게 되므로, 이 클래스의 값을 받아오기 위해 바인드를 해주어야했다.
비록 값을 담은 구조를 Object로 변경하면서 this를 피해 오류가 없어지긴 했지만, 다음에는 오류 발생 과정을 더욱 틈틈히 작성해야겠다.

또한, 이벤트 함수에 인자값을 전달하기 위해 단순히 onClick = {this.clickEvent(arg)} 이렇게 작성하면 안되고

`onClick = {this.clickEvent.bind(this,arg)}`
`onClick = {(e) => this.clickEvent(e)}`

다음과 같이 작성해주어야 제대로 이벤트의 인자값이 전달된다.

만약 함수형 컴포넌트였다면 this바인딩을 할 필요가 없으니 그냥 onClick = {clickEvent(arg)} 로 작성하면 되니 더 간편하게 작성할 수 있다. 이래서 함수형을 많이 사용하는구나

react 함수 전달

위의 험난한 과정을 거쳐 이벤트 실행을 테스트하는데 이벤트가 실행되지 않는 문제가 발생했다.
<User onClick = {this.checkResult.bind(this, 0)}>{this.state.values[0].emoji}</User>
이렇게 만들어진 컴포넌트에 onClick props로 전달한다는 의미여서
User 컴포넌트에 onClick이 실행될 버튼에 이벤트를 넣어주는 과정이 필요했다.

function User({onClick, children}){
    return (
        <button onClick={onClick} className = "btn">{children}</button>
    )
}

중요한 점은 onClick으로 보냈으니 props 이름도 onClick으로 설정해줘야 한다.
이렇게 이벤트를 button에 입력해줘야 제대로 작동한다! 컴포넌트에 입력해봤자 의미 없음.

함수 파라미터로 setState 설정하기

win(){
    alert("이겼다!!!!");
    this.setState((prev) => {
      return {user : prev.user + 1}
    })

  }

  lose(){
    alert("졌다!!!!!!!!");
    this.setState((prev) => {
      return {gamer : prev.gamer + 1}
    })

  }
  
  // 위의 두 함수를 합친 function을 만들고 싶어 다음과 같이 합쳤다

  result(winner){
    alert(winner === "gamer" ? "졌다!!!!!" : "이겼다!!!!")
    this.setState((prev) => {
      return {winner : prev.winner + 1}
    })
  }

입력받는 winner값에 따라 상태가 변화되도록 하고 싶었는데 setState에서는 적용이 되지 않았다.

result(winner){
    alert(winner === "gamer" ? "졌다!!!!!" : "이겼다!!!!")
    this.setState((prev) => {
      return {[winner] : prev[winner] + 1}
    })
  }

파라미터 값을 대괄호 안에 넣어주니 원하는 대로 작동했다!

새롭게 배운 점

CSS는 컴포넌트 별로 생성하기

최상위 js 파일에 하위 컴포넌트들의 css를 작성해도 적용이 되긴 하지만 더욱 효율적으로 코드를 짜기 위해 컴포넌트 별로 css파일을 생성하는게 좋다고 한다. 그래서 이번에 짤 때도 컴포넌트 별로 css 파일을 작성하였다.

모든 변수를 JSX에 입력시 항상 {}로 감싸주기

클래스 이름을 문자열과 입력받은 변수를 넣고 싶어 방법을 찾아보다가 `~${}~` 을 입력하면 괜찮지 않을까 싶어 className= `c1 ${c2}` 를 입력해보았다. 오류가 발생해 찾아보니 항상 괄호를 입력하고 그 안에 className= {`c1 ${c2}`} 이렇게 입력하면 돌아간다고 해서 수정하니 제대로 동작했다.

  • 2022.01.02
    클래스컴포넌트에서 함수형 컴포넌트로 변경
profile
PRE-FE에서 PRO-FE로🚀🪐!

2개의 댓글

comment-user-thumbnail
2021년 12월 19일

와! 감사합니다 :) 실제로 이렇게 구현된 것을 보니까 엄청 신기한 경험이네요~ 화면도 예쁘게 잘 만들어 진것 같아요!! 그리고 배포까지! 멋져요 +_+bb

1개의 답글