상태 관리 라이브러리 없이 다른 색깔 찾기 게임을 구현 한적 있습니다!
numble에서 간단한 피드백을 주셨고 리액트 상태 관리에 대해 공부하던 중 당시 읽고 넘어 가기만 했던 프로젝트를 개선해 보았습니다.
기존 코드는 다음 글에서 확인할 수 있습니다.
https://hoime.tistory.com/38?category=534509
✔ 개선 사항
1. 불필요한 상태가 정의 되어있습니다.
- 스테이지가 올라 갈 때 마다 사각형 갯수를 다르게 해야하는데, stage에 따라 itemCnt를 계산하여 반복문 통해 순차적인 배열을 생성해 렌더링 했었습니다.
- stage값이 이미 state로 정의 되었고 stage따라 계산만 하면 되는 단순 배열이기 때문에 굳이 배열로 따로 상태 관리 하지 않아도 되게 바꾸었습니다.
// stage 통해 itemCnt 계산 후
[...Array(itemCnt)].map((_, index)=> (...))
// 이런 패턴으로 개선
2. 상위 컴포넌트에서 모든 상태와 handler 함수를 정의 하고 하위 컴포넌트로 전달 하는 패턴
- 당장의 가독성이 좋지 않고, 추후 변경 사항이 생겼을 때 손대기 어려운 컴포넌트가 될 수 있습니다.
- customHook 과 useReducer()를 사용해 개선 하였습니다.
- random 값을 생성하는 단순 함수는 utils라는 폴더를 만들어 분리 하였습니다.
✔ 폴더 구조
✔ useReducer, useGame
- 개선 사항의 핵심은 두 컴포넌트라고 생각합니다.
- useReducer의 경우 리덕스를 공부했다면 쉽게 이해할 수 있습니다.
- useReducer 함수를 통해 state와 dispatch 함수를 받아 올 수 있습니다.
// reducer.js
import getRandomState from "../utils/random";
export const initialState = {
stage: 1,
score: 0,
remainSecond: 0,
isPlay: true,
baseColor: "",
answerColor: "",
answerIndex: 0,
};
export function reducer(state, action) {
switch (action.type) {
case "INIT_GAME":
return {
...state,
...getRandomState(1),
stage: state.stage,
score: state.remainSecond,
remainSecond: 15,
isPlay: true,
};
case "SELECT_CORRECT":
return {
...state,
...getRandomState(state.stage + 1),
remainSecond: 15,
stage: state.stage + 1,
score: state.score + Math.pow(state.stage, 3) * state.remainSecond,
};
case "SELECT_WORONG":
return {
...state,
remainSecond: Math.max(state.remainSecond - 3, 0),
};
case "COUNT_TIMER":
if (!state.isPlay) {
return state;
}
if(state.remainSecond <= 0) {
return {
...state,
isPlay : false,
};
}else{
return {
...state,
remainSecond: state.remainSecond -1,
};
}
default:
throw state;
}
}
- useReducer 함수의 인자로 initialState를 넘겨 줘야 되는데 꼭 여기서 안해도 되긴 합니다. export로 정의 하여 useGame에서 import하여 사용하였습니다.
// useGame.js
const useGame = () => {
const [gameState, dispatch] = useReducer(reducer, initialState);
// 중략...
}
export default useGame;
✔ 느낀점
- 상태 관리에 대해 공부 할수록 리액트의 핵심적인 컨셉이 이게 아닐까 라는 생각이 듭니다.
- 단순 구현이 아니라 효율적인 상태관리가 필요하다는 것을 절실히 느낍니다.
- 리덕스를 공부하며 재사용되거나 자주 쓰이는 상태들을 전역적으로 store에서 관리를 하면 좋겠구나 생각했는데 custom Hook을 에서 첫 로딩시 상태 (effect)와 이벤트 핸들러를 정의 해서 리턴해주는 식으로 하는 것은 혼자 했으면 생각도 못했을 것 같다.
- 특히 custom Hook을 앞으로 최대한 활용해봐야 겠다고 느낌, 처음에 내가 했던 방식은 App.js에 useState랑 온갖 함수를 잔뜩 써놨는데 random 함수를 분리하고 custom hook까지 쓰니까 App.js 비교도 안되게 간결 해짐...
// App.js
import React from "react";
import Board from "./components/board";
import Header from "./components/header";
import useGame from "./hooks/useGame";
const App = () => {
const {gameState, action} = useGame();
console.log("App state : ", gameState);
return (
<>
<Header {...gameState} />
<Board {...gameState} onSelect={action.clickHandler} />
</>
);
};
export default App;
✔ 전체 코드
https://github.com/HomieKim/React_PlayGround/tree/main/diff-color-refactoring
✔ 참조
https://sumini.dev/retrospective/002-numble-thinking-in-react/
'react' 카테고리의 다른 글
[React 상태관리] react-query 입문 하기 (0) | 2022.04.13 |
---|---|
react 무한스크롤 구현하기(react-intersection-observer, createAsyncThunk 사용) (0) | 2022.04.07 |
[React 상태관리]리덕스 이해하기 + todoList 만들기 (0) | 2022.03.27 |
Zillow 클론코딩 회고 (0) | 2022.03.05 |
[Numble] 다른 색깔 찾기 게임 (0) | 2022.01.27 |
댓글