Typescript와 React를 활용한 Wordle 게임

woodylovesboota·2023년 9월 3일
0
post-thumbnail

Typescript로 react를 사용하는 방법을 알고난 후 지난번에 만들었던 wordle을 ts로 바꿔보았다.

Typescript를 사용하게 되면 기대했던 대로 코딩이 편해지는 지 확인하고 싶었고, error 발생도 js보다 구체적으로 일어나는지 궁금했다.

결과부터 말하자면 typescript를 이용하는 것이 기대했던 것 이상으로 좋은 방법이라는 것을 느꼈다.

변수 하나, props 하나마다 type을 지정해 주어야 한다는 것이 신경쓰이는 점이였지만, 선언 과정에서 변수에 들어갈 값을 한정하고 구현하는 것이 auto complete 등 이후의 개발 과정이나 프로그램 실행 단계에서 발생하는 오류를 의미있게 줄일 수 있었다.

구현


기본적인 structure나 method는 이전에 구현한 js 코드와 크게 다르지 않게 구현하였다.

APP
|
-----Word
|	|
|	 ---Letter
|
----ResultPage

Word는 사용자가 입력하는 한 단어를 나타내는 component이며 5개의 Letter 로 이루어져 있다.

사용자는 총 7개의 Word를 통해 정답을 찾아야 하고 게임이 종료되면 ResultPage가 나타나게 구현하였다.

사용자가 한 단어를 입력할 때마다 각 문자의 정답 여부를 확인하게 된다.

  1. 위치와 단어 둘다 맞으면 - 초록색
  2. 단어는 맞았지만 위치가 다르다면 - 노란색
  3. 위치와 단어 둘다 맞지 않는다면 - 회색

추가적으로 기존에 구현했던 것과 달리 Letter에 color를 입힐 때 class를 이용하지 않고 props를 이용하였다. 아무래도 React에서는 직접 DOM을 건드리는 것이 신경쓰이기도 했고 props를 이용하면 element에 class를 추가했다 지웠다 하는 작업을 할 필요가 없기 때문에 props를 통해 Letterbackground color를 바꿔주었다.

{colors.map((color, index) => (
  <Letter
    key={index}
    bgcolor={
      color === "G"
        ? "#539165"
      : color === "Y"
        ? "#F7C04A"
      : color === "B"
        ? "gray"
      : "#dcdde1"
    }
    />
))}
interface IColor {
  bgcolor: string;
}

const Letter = ({ bgcolor }: IColor) => {
  return <Input bgcolor={bgcolor}></Input>;
};

const Input = styled.input<IColor>`
  background-color: ${(props) => props.bgcolor};
  ...
`

이 때 typescript에서는 interface를 통해 Letter의 props는 bgcolor 하나만 존재하는 것과 bgcolor의 type이 string이라는 것을 제한할 수 있다. Letterbgcolor 이외의 다른 props가 전달되거나 bgcolornumber, booleanstring이 아닌 값이 전달된다면 프로그램은 실행되지 않고 error를 반환할 것이다.

또한 문제의 정답인 answer 와 게임의 현재 상태를 표시해주는 isFinish 등의 state는 Recoil을 이용하여 전역 State로 이용하였다.

Recoil은 state 관리하는 tool이라고 알게됬는데 은근 사용 방법이 쉬워서 간단하게 사용해 보았다.

import { atom } from "recoil";

export enum STATUS {
  "NOT_FINISHED",
  "WIN",
  "LOSE",
}

export interface IResult {
  result: STATUS;
}

export const answerState = atom({
  key: "answer",
  default: "",
});

export const isFinishState = atom<STATUS>({
  key: "isFinish",
  default: STATUS.NOT_FINISHED,
});

key는 state를 알 수 있는 고유 값이고 default는 state의 초기값이다.

state를 component에서 사용하기 위해선 useRecoilState() 를 사용하여 기존 useState() 처럼 사용 가능하다. 혹은 state value와 modifier function을 따로따로 사용하는 것도 가능하다.

const [answer, setAnswer] = useRecoilState(answerState);

const answer = useRecoilValue(answerState);

const setAnswer = useSetRecoilState(answerState);

answerstring으로 선언 하였고, 게임의 상태를 나타내주는 isFinish는 interface 를 이용하여 "NOT_FINISHED", "WIN", "LOSE" 중에 하나의 값을 갖도록 선언하였다.

게임의 상태는 다음과 같다.

  1. answer를 정확하게 맞춰 다섯칸 모두 초록색이 될 때 : WIN
  2. 7번의 기회 동안 정답을 맞추지 못했을 때 : LOSE
  3. 아직 정답을 맞추지 못했고 기회가 남아있을 때 : NOT_FINISHED

ResultPage는 게임이 종료되었을 때 결과 창을 나타내는 component이며 게임의 승패 여부, 정답이 무엇이였는지를 알려준다.

isFinishedNOT_FINISHED일 때는 숨겨놨다가 상태가 바뀌게 되면 보여지게 하는 식으로 구현하였다.

top: ${(props) => (props.result === STATUS.NOT_FINISHED ? "-100vh" : 0)};

마치며


typescript를 사용하여 구현을 해봤는데 생각보다 코드를 편하게 짤 수 있었다. 미리 interface를 지정해 놓으면 auto complete도 잘되고 변수를 잘못 넣으면 error를 반환하니깐 시행착오를 많이 줄일 수 있었다.

새로 만드는 김에 Recoil 같은 새로운 tool도 써서 그런지 코드도 이전보다는 덜 복잡하게 정리되었다.

0개의 댓글

관련 채용 정보