Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions week3/assignment/assignment3/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
8 changes: 8 additions & 0 deletions week3/assignment/assignment3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
38 changes: 38 additions & 0 deletions week3/assignment/assignment3/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
14 changes: 14 additions & 0 deletions week3/assignment/assignment3/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id = "modal"></div>
<div id = "root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions week3/assignment/assignment3/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "assignment3",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"eslint": "^9.13.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.11.0",
"vite": "^5.4.10"
}
}
1 change: 1 addition & 0 deletions week3/assignment/assignment3/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions week3/assignment/assignment3/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Global, ThemeProvider} from '@emotion/react';
import Home from './Home'
import global from './styles/global'
import {Theme} from './styles/theme'

function App() {

return (
<>
<ThemeProvider theme={Theme}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThemeProvider까지 사용하시다니... 꼼꼼함 최고네여👏

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

세미나 내용에 있었어서 한 번 적용해보고 싶었습니다 ㅎㅎ 감사합니다!

<Global styles={global} />
<Home />
</ThemeProvider>
</>
)
}

export default App;
48 changes: 48 additions & 0 deletions week3/assignment/assignment3/src/Home.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import styled from "@emotion/styled";
import { useState } from 'react';
import Header from './components/Header';
import Game from './components/Game';
import Rank from './components/Rank'

const Home = () =>{
const [menu, setMenu] = useState("game");
const [level, setLevel] = useState(1);
const [timer, setTimer] = useState(0);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timer 값을 부모 컴포넌트에서 관리함에 따라 게임 컴포넌트나 다른 헤더 내부 요소들이 무지막지하게 리렌더링 되고 있습니다...!🥹
최대한 리렌더링을 최소화할 수 있는 방법을 생각해보시는 게 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 설계할때 고려하지 못했던 부분인데 정말로 불필요한 렌더링이 많이 되는 것 같아요 반영해서 수정해볼게요 좋은 리뷰 감사합니다~~


const handleMenuChange = (menu) => {
setMenu(menu);
}
const handleLevelSelect = (level) => {
setLevel(level);
};
const handleTimerChange = (timer) => {
setTimer(timer);
};
Comment on lines +12 to +20

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setState 자체를 props로 전달하지 않고 함수 만들어서 전달하는 방식 좋네요.
화랑 오빠 아티클이 생각이 납니다...
https://velog.io/@thisishwarang/React-setState-%EC%9E%90%EC%B2%B4%EB%A5%BC-props%EB%A1%9C-%EC%A0%84%EB%8B%AC%ED%95%98%EC%A7%80-%EB%A7%90%EC%95%84%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 몰랐는데 자체를 넘기지 않는게 좋갰네요! 앗싸 새로운거 배워갑니다!


return (
<>
<Header
menu={menu}
timer={timer}
handleMenuChange={handleMenuChange}
handleLevelSelect={handleLevelSelect}
/>
<Main>
{menu === "game" ? (
<Game level={level} timer={timer} handleTimerChange={handleTimerChange}/>
):(
<Rank/>
)}
</Main>
</>
);
};

const Main = styled.main`
width: 100%;
height: 100%;
margin: 0 auto;
padding-top: 2rem;
`;

export default Home;
111 changes: 111 additions & 0 deletions week3/assignment/assignment3/src/algorithm/GameAlgorithm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { useState, useEffect } from 'react';

// 숫자를 섞어주는 함수
const randomArray = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
};

// 숫자를 생성해서 랜덤으로 배열에 넣는 함수
const createNums = (min, max) => {
const nums = [];
for (let i = min; i <= max; i++) {
nums.push(i);
}
return randomArray(nums);
};

// 결과 저장 및 local 저장소에서 넣고 빼기
const saveResult = (time, level) => {
const result = {
timestamp: new Date().toISOString(),
time,
level,
};
const savedResults = JSON.parse(localStorage.getItem('results')) || [];
savedResults.push(result);
localStorage.setItem('results', JSON.stringify(savedResults));
};

// 게임 알고리즘
const gameAlgorith = (level, timer, handleTimeChange) => {
const rowNum = level + 2;
const boardSize = rowNum * rowNum;
const maxNum = boardSize * 2;
const [currentNum, setCurrentNum] = useState(1);
const [timeId, setTimeId] = useState(null);
const [isFinish, setIsFinish] = useState(false);
const [beforeNums, setBeforeNums] = useState(createNums(1, boardSize));
const [afterNums, setAfterNums] = useState(createNums(boardSize + 1, maxNum));
Comment on lines +41 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 상태관리 변수이름이 추상적인 것 같습니다! 조금 더 직관적인 이름으로 바꾸거나 각주를 추가하는 방법 추천 드립니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 직관적인 이름이나 각주 달아보도록 하겠습니다!!


const checkNumberClick = (number) => {
// 게임을 시작 할때 타이머를 시작시키는 로직
if (currentNum === 1) {
const id = setInterval(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 요기 타이머 관련 변수를 id라고 지은 이유가 혹시 있을까요?! 조금 더 직관적이면 좋을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 큰 이유가 없었는데 더 직관적인 변수명을 사용하는게 좋을 것 같아요! 반영해서 수정하겠습니다 ㅎㅎ

handleTimeChange((previousTime) => {
const updatedTime = (previousTime + 0.01).toFixed(2);
return parseFloat(updatedTime);
});
}, 10);
setTimeId(id);
}
Comment on lines +46 to +54
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 보니까 currentNum은 다음에 눌러야할 카드를 보여주는 상태인 것 같네요!
근데 처음 게임을 시작할때를 생각해보면, 클릭한 카드의 번호 == 1이어야 할거 같아요.
currentNum 대신에 내가 누른 카드 번호로 바꿔주시면 좋을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 말씀해주신대로 클릭한 number가 1일때 타이머가 시작되는게 맞는 것 같아요!! 반영하도록 하겠습니다


if (currentNum <= boardSize) {
const newNum = afterNums.pop();
const updateBoard = beforeNums.map((num) =>
num === number ? newNum : num
);
setBeforeNums(updateBoard);
}
// 카드를 없애는 로직
else if (currentNum > boardSize && currentNum < maxNum) {
const updatedBoard = beforeNums.map((num) =>
num === number ? null : num
);
setBeforeNums(updatedBoard);
}
Comment on lines +56 to +69
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 둘다 if 조건에 내가 누른 카드의 수가, 눌러야 할 숫자인지 판별하는 조건이 없습니다! 추가해주세욥

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 반영해서 수정하도록 하겠습니다!


setCurrentNum(currentNum + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 카드를 클릭할때마다 currentNum가 증가하고 있는데요! 요거는 알맞은 카드를 선택할때만 작동하도록 조건문을 걸어주시면 될 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 이 부분을 고려해야 알맞은 카드만 선택이 가능할 것 같아요 좋은 리뷰 감사합니다!


if (number === maxNum) {
clearInterval(timeId);
saveResult(timer, level);
setIsFinish(true);
return;
}
Comment on lines +73 to +78
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: maxNum을 누르면 게임이 끝나고 있어요! 이렇게 되면 남은 숫자가 있는데도 게임이 종료되어서
요기 조건문을 수정해주시면 좋을 것 같습니다!
if(number === maxNum && number === currentNum) 이렇게 조건 바꿔주시면 해결될 것 같습니다 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 정말 고려하지 못했던 부분이네요 좋은 리뷰 감사합니다!! 반영하도록 하겠습니다

};

const closeModal = () => {
setBeforeNums(createNums(1, boardSize));
setAfterNums(createNums(boardSize + 1, maxNum));
setIsFinish(false);
setCurrentNum(1);
handleTimeChange(0);
};

useEffect(() => {
setBeforeNums(createNums(1, boardSize));
setAfterNums(createNums(boardSize + 1, maxNum));
setIsFinish(false);
clearInterval(timeId);
setCurrentNum(1);
handleTimeChange(0);
return () => clearInterval(timeId);
}, [level]); //level이 변경될 때 마다 렌더링이 되도록
Comment on lines +81 to +97

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

closeModal과 useEffect에서 동일한 함수들이 호출되고 있는 것 같은데 중복되는 함수들은 하나의 함수로 묶어서 호출하는 건 어떨까요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 저도 비슷하게 남겼는데 공감!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동의합니다!! 말씀해주신대로 수정해볼게요

Comment on lines +81 to +97
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3:
모달 닫기 함수와 useEffect 에서 아래의 로직이 반복되어 동작하는데요! 요친구 함수로 만들어서 사용하면 더 좋을 것 같네요!

    setBeforeNums(createNums(1, boardSize));
    setAfterNums(createNums(boardSize + 1, maxNum));
    setIsFinish(false);
    setCurrentNum(1);
    handleTimeChange(0);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 중복되는 부분 함수로 만들어서 적용해보겠습니다!


return {
rowNum,
maxNum,
beforeNums,
currentNum,
isFinish,
closeModal,
createNums,
checkNumberClick,
};
};

export default gameAlgorith;
22 changes: 22 additions & 0 deletions week3/assignment/assignment3/src/algorithm/formatDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const formatDate = (timestamp) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

함수 따로 파일로 분리해서 사용하는 방법 좋네요...👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

완전!! 로직분리까지 최고 🙌

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다 ㅎㅎ

const dateObj = new Date(timestamp);

let [year, month, day, hour, minute, second] = [
dateObj.getFullYear(),
dateObj.getMonth() + 1,
dateObj.getDate(),
dateObj.getHours(),
dateObj.getMinutes(),
dateObj.getSeconds(),
];

const period = hour >= 12 ? '오후' : '오전';
hour = hour % 12 || 12;
Comment on lines +13 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 오호 오전 오후까지 고려하셨다니 세심한 생각 한수 배웠습니다 !!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다 ㅎㅎ


const pad = (num) => num.toString().padStart(2, '0');
const formattedDate = `${year}.${pad(month)}.${pad(day)}`;
const formattedTime = `${period} ${pad(hour)}시 ${pad(minute)}분 ${pad(second)}초`;
return `${formattedDate} ${formattedTime}`;
};

export default formatDate;
Loading