[토이 프로젝트] 장미전쟁 score tracker 만들기: 이번 tap 순서인 user의 배경색 지정, board 원소 클릭 시 tap 순서에 맞게 cell 숫자 변경

이민선(Jasmine)·2023년 6월 4일
0
post-thumbnail

이번 포스팅은 점수 알고리즘을 짜기 전 준비 단계로 볼 수 있다.

user1과 user2가 공통으로 사용하는 User 컴포넌트에는 userNumber라는 prop을 새로 넘겨주었다.

User 컴포넌트에서 현재 tap 순서 전역 상태 접근, onClick 내부에서 action 전달

GameUser.tsx

function User({ userNumber, src, userName }: UserProp) {
  const dispatch = useDispatch();
  const currentGameTurn = useSelector(
    (store: RootState) => store.tapTurnStore.tapTurn
  );
  const onClick = () => {
    dispatch(getWhoseTurnItIs({ tapTurn: userNumber }));
  };
  // prop으로 받은 userNumber(1, 2 중에 하나)와, 현재 순서인지 boolean 값을 출력
  console.log(userNumber, currentGameTurn === userNumber);
  .
  .
  (생략)

이렇게 각 user의 이름을 클릭하면 해당 user가 board에 있는 점수를 tap할 수 있는 상태가 되게 할 것이다.

그리고 누가 tap할 차례인지 한 눈에 알 수 있도록 styled-components에 prop을 넘겨서 현재 순서인 user의 이름에 배경색을 줘야겠다.

현재 tap 순서에 해당하는 user의 배경색 지정

// isMyTurn이라는 boolean 값의 prop을 넘기고
      <UserWrapper onClick={onClick} isMyTurn={currentGameTurn === userNumber}>
export const UserWrapper = styled.div<UserWrpperProps>`
  display: flex;
  justify-content: center;
  align-items: center;
  height: 55px;
  font-size: 30px;
  //prop으로 넘겨서 조건 분기하여 배경 지정
  background-image: ${(props) =>
    props.isMyTurn ? "linear-gradient(150deg, white, pink)" : "transparent"};
`;


클릭할 때마다 user의 순서가 바뀌고 배경으로 한 눈에 알 수 있다.
이제 user의 tapTurn에 따라 board를 클릭했을 때 숫자가 변하도록 할 것이다.

  • user1 순서일 경우: 0-1-0-1-0-1-0-1-0...
  • user2 순서일 경우: 0-2-0-2-0-2-0-2-0...

렛쓰기릿..

GameBoard.tsx (미리 얘기하지만 실패작임 🤣)

// GameBoard의 cell에 아래와 같은 onClick을 걸어주었다.
  const onClick = (event: React.MouseEvent<HTMLTableCellElement>) => {
    if (event.currentTarget.innerText === "0") {
      event.currentTarget.innerText = tapTurn.toString();
    } else {
      event.currentTarget.innerText = "0";
    }
  };


와우~~ 클릭하니까 숫자들이 변해!! 너무 짜릿해~~~ user1 차례일 때는 0을 누르면 1로 변하고 1을 누르면 0으로 변한다. uesr2 차례에는 0을 누르면 2가 되고, 2를 누르면 0이 된다.

이제 대망의 알고리즘 짜는 시간?!!일까?!!
DFS 방식으로 GameCell 2차원 배열의 정보를 가지고 user1과 user2의 점수를 console 출력해볼 것이다. 과연 할 수 있을 것인가..!! 떨림...설렘...

Uhm 근데 문제가 생겼다.
알고리즘을 짜려면 user들이 클릭한 숫자인 1과 2가 반영된 table이 필요한데, event.currentTarget.innerText만 변경했기 때문에 화면에 출력되는 숫자만 변하고 table에 있는 원소들은 계속 전부 다 0이다.

의도치 않은 결과: 화면에 출력되는 숫자는 변하지만 table의 원소는 불변.

table 원소 자체를 바꿔줘야 하는구나! 난이도 별 1개 증가~
한 번 처리해보자.

오.. 쉽지 않아보이는 난관을 만났다.

화면에 출력할 때와 다르게 console로 출력하니 user1의 차례 때는 2가 전부 다 0으로 변해있고, 다시 user2 차례로 돌아오면 1이 전부 다 없어져 있다. 1과 2가 동시에 Board에 떠있어야 점수를 계산할 수 있을텐데?

Hmm...고뇌 중..

gameboard도 store에서 상태 관리를 하면 숫자들이 유지되겠지?!

BoardStore 생성하러 가야겠다.

GameBoard도 전역 상태 관리하여 난관 극뽀옥

BoardStore.tsx

import { PayloadAction, configureStore, createSlice } from "@reduxjs/toolkit";

type GameBoard = number[][];

type GameBoardPayload = {
  currentUser: number;
  rowIdx: number;
  columnIdx: number;
};

// 0으로 가득한 2차원 배열 생성하여 initial state으로 지정
const initialGameBoardState: GameBoard = [...Array(9)].map((_) =>
  [...Array(9)].map((_) => 0)
);

export const GameBoard = createSlice({
  name: "GameBoardReducer",
  initialState: initialGameBoardState,
  reducers: {
    getGameBoard: (
      state: GameBoard,
      action: PayloadAction<GameBoardPayload>
    ) => {
      // action으로 전달 받은 행, 열 인덱스에 해당하는 원소를 currentUser 숫자와 0 사이에서 번갈아가며 나타나게 만듦.
      const [i, j] = [action.payload.rowIdx, action.payload.columnIdx];
      if (state[i][j] === 0) {
      // immer 라이브러리 덕분에 mutate state이 허용됨.
        state[i][j] = action.payload.currentUser;
      } else {
        state[i][j] = 0;
      }
    },
  },
});

export const gameBoardStore = configureStore({ reducer: GameBoard.reducer });
export const { getGameBoard } = GameBoard.actions;

GameBoard.tsx

function GameBoardContainer() {
  const dispatch = useDispatch();
  const table = useSelector((store: RootState) => store.gameBoardStore);
  const tapTurn = useSelector((store: RootState) => store.tapTurnStore.tapTurn);

  const onClick = (rowIdx: number, columnIdx: number) => {
    // store에 변경하고 싶은 행, 열의 인덱스 전달
    dispatch(getGameBoard({ currentUser: tapTurn, rowIdx, columnIdx }));
    console.log(table);
  };
.
.
(중략)
.
.
// map으로 뿌려주는 table 원소인 GameBoardCell 컴포넌트에 onClick을 연결해주고 element를 렌더링해준다.
                  <GameBoardCell
                    key={rowIdx + "" + columnIdx}
                    onClick={() => onClick(rowIdx, columnIdx)}
                  >
                    {element}
                  </GameBoardCell>

후.. 다행히도 성공!! 하나의 난관을 넘었다 ㅎㅎㅎㅎ
BoardStore를 생성해서 보드판도 redux store로 관리하니 user1과 user2의 숫자가 동시에 보이지 않던 문제도 해결되었고, 화면에 렌더링도 실시간으로 잘된다.

이제 진짜 알고리즘을 짜보자.
길어져서 다음 포스팅에서 다뤄야할 듯..?!
씨유쑨~~!

profile
기록에 진심인 개발자 🌿

0개의 댓글