react - Tic Tac Toe

김동하·2020년 11월 2일
0

react

목록 보기
6/31

react로 만드는 신나는 틱택토다.

이런 신나는 게임이다.

게임 룰

https://namu.wiki/w/%ED%8B%B1%ED%83%9D%ED%86%A0

링크 참고

세팅

먼저 리액트로 세팅하기 전에 바닐라 자바스크립트로 틱택토를 어떻게 만드는지 알아보자!

바닐라 js에서 틱택토

3x3 게임판이 있고 하나를 클릭하면 O가 그려지고 다음 플레이어로 넘어간다.

클릭 이벤트가 발생하면 클릭 함수가 호출되고 cell은 현재 사용자가 클릭한 div, currentClass는 O를 할지 X를 할지 결정하는 변수다. 기본 값을 false로 해둬서 X가 먼저 시작한다. placeMark함수는 class를 currentClass로 add해서 O나 X가 찍히게 하는 함수다.

그러면 매턴마다 win, draw를 체크해야 한다. check, draw가 아니라면 swapTurn함수와 hoverClass를 호출하는데 호버하면 O나 X표시가 나는 함수인데 이건 부가적인 것이니 패스하고 swapTurn은 currentClass를 아주 깔쌈하게 바꿔주는 함수다.

아름다워...

아무튼 사용자가 board를 클릭할 때마다 checkWin 함수가 호출되는데 checkWin은 아주 아주 아주 신박하고 어렵고 놀랍고 아름다운 녀석이다.
게임 룰에 의하면 한 줄, 혹 대각선이 같은 모양이어야 한다. 이것을 어떻게 체크하나면 일단 winningArray로 이길 수 있는 경우의 수를 배열에 담고

현재까지 사용자가 누른 div들의 인덱스가 저기 포함되는지 찾으면 된다.

return이 무려 3개... return만 보이면 가슴이 콩딱콩딱 뛴다...

해석하자면 checkWin 함수에 currentClass가 들어가는데 1차로 winning array에 some을 해서 모든 배열을 펼친다. 그리고 그 배열들에 every로 또 인덱스들을 펼치는데 이제 사용자가 누른 (지금까지) div의 인덱스가 모두 (every)를 만족해야 true를 반환한다. 진짜 너무 어렵지만 알고 싶어서 이 함수만 보면 설렌다.

아무튼 draw 함수의 경우 아무도 한 줄을 만족하는 경우가 없으면 되는데

전개 연산자로 모든 cell를 검사해서 모두가 x혹 o를 가지고 있으면(사이좋게 )true를 반환하는 것. 아무튼 이제 리액트로 만들어보장

다시 리액트로

일단 기본 세팅은 이러하다.

App 컴포넌트는 Game 컴포넌트를 렌더한다.

Game 컴포넌트는 board를 만드는 html이 있고 Board 컴포넌트를 랜더한다.

Board 컴포넌트는 renderSquare 함수를 통해 square에 렌더하면서 숫자를 주입한다.

마지막으로 square는 하나의 square로 board의 자식이니까 board의 props를 받는다.

숫자 넣기

Square 컴포넌트에 value를 props으로 준다. Board.js 안 renderSquare 함수에서 실행하면 된다.

각 row에 renderSquare의 return 값, 즉 <Square>를 주면 되고 square의 벨류 값은, 즉 props는 Suqare 컴포넌트 안에서 받으면 된다.

아름답다...

클릭하면 square에 X표시

square를 클릭하면 X 표시를 치기 위해 onClick를 버튼에 props로 준다. 그리고 state를 사용해야 하는데 클릭한 것을 "기억"해야 한다.

출처 : https://ko.reactjs.org/tutorial/tutorial.html

state에 value 값을 저장하고 setState로 state를 변경한다.

죄송합니다. prettier가 먹지 않아 정렬이 되지 않습니다.

클릭하면 square에 번갈아 표시

승자를 확인하기 위해서 9개의 Square 컴포넌트가 가지고 있는 state를 하나로 모아야 한다. 그렇기 위해서 부모 컴퍼넌트인 Board에 게임 상태를 저장하는 것이 가장 좋다. 각 Square에 숫자를 넘겨주었을 때 값이 Board 컴포넌트는 각 Square에 prop을 전달하는 것으로 무엇을 표시할 지 알려준다!

그럼 이제 state를 부모 컴포넌트로 끌어올려보자! 일단 Board에 state에 Array(9).fill(null)로 배열을 state 값으로 준다. 여기서 중요한 것은 맨 처음 Board에서 value를 props로 전달했고 그 다음에 Square에서 자체적으로 state로 value 값을 "X"표시로 변경했다. 현재 Square는 Board에서 전달한 value prop을 무시하고 있다!!!!

그러므로 이제 다시 props를 전달해야 한다. 각 Squaredp 현재 값("X", "O", null)을 표현하도록 Board를 수정한다.

이제부터 헷갈리기 시작하는데 정신 똑바로 차려야지!

이제 Square를 클릭할 때 이벤트를 줘야 한다. Board 컴포넌트는 사각형에 무엇이 표시되었는지를 관리하므로 Square가 Board를 변경할 방법이 필요하다! Board에서 Square로 함수를 전달하고 Square는 사각형을 클릭할 때 함수를 호출한다.

컴포넌트는 자신이 정의한 state에만 접근할 수 있으므로 Square에서 Board의 state를 직접 변경할 수 없다.

Board에서 Square로 value, onClick 두 개의 props를 전달했다. onClick prop은 Square를 클릭하면 호출되는 함수다. 이제 Square를 변경해야 한다!

Square는 상태를 유지할 필요가 없으니까 state를 삭제하고 setState대신 onClick prop으로 this.props.onClick()을 받는다. 즉, Square를 클릭하면 Board에서 받은 onClick이 실행된다.

버튼 클릭하면 생기는 일 정리

Board와 Square 둘 다 prop으로 onClick을 줘서 헷갈렸는데 3번이 그 이유인 듯 하다!!

Board에서 state 관리

이제 Board에 handleClick 함수를 정의해야 한다. 진짜 혁명적이고 놀라워서 리액트가 너무 사랑스럽다.

handleClick이 실행되면 i 라는 인자를 받는다. i는 클릭한 사각형이 가지고 있는 value! 그러면 squares라는 변수를 만들어서 원래 state에 존재하는 squares를 복사한다. 그리고 i 인덱스에 해당하는 곳을 "x"로 만들고 setState를 이용해 바뀐 squares를 저장한다.

와... 진짜 대단하다... 가슴이 콩닥콩닥 뛴다.

부모인 Board 컴포넌트에 state를 저장한다. Board 상태가 변화하면 Square 컴포넌트가 자동으로 렌더된다.

Square 컴포넌트가 더 이상 state를 유지하지 않기 때문에 Square 컴포넌트는 Board 컴포넌트에서 값을 받아 클릭될 때 Board 컴포넌트로 정보를 전달한다.

출처 : https://ko.reactjs.org/tutorial/tutorial.html

profile
프론트엔드 개발

0개의 댓글