-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3주차 기본/심화 과제] 🍚 점메추 🍚 #4
base: main
Are you sure you want to change the base?
Changes from all commits
412dad5
36e128e
c99db20
9b1a195
1937506
0d41769
dae31af
a7b4409
6bd0124
7917026
4a399b9
567fa12
da8d2bd
3a1ace5
7617813
86fb735
c65640e
4c4d6cc
11076c8
2691036
c2d12dd
d61afe5
12eed6a
4697aab
5fd6995
c861290
00922f5
38f798b
3f50410
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"env": { | ||
"browser": true, | ||
"es2021": true | ||
}, | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:react/recommended", | ||
"plugin:@typescript-eslint/recommended" | ||
], | ||
"overrides": [], | ||
"parser": "@typescript-eslint/parser", | ||
"parserOptions": { | ||
"ecmaVersion": "latest", | ||
"sourceType": "module" | ||
}, | ||
"plugins": ["react", "react-hooks", "@typescript-eslint", "prettier"], | ||
"rules": { | ||
"quotes": ["error", "single"], | ||
"no-duplicate-imports": "error", | ||
"no-console": ["warn", { "allow": ["warn", "error", "info"] }], | ||
"no-unused-vars": "error", | ||
"no-multiple-empty-lines": "error" | ||
}, | ||
"settings": { | ||
"import/resolver": { | ||
"typescript": {} | ||
} | ||
} | ||
} |
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? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"printWidth": 100, | ||
"tabWidth": 2, | ||
"singleQuote": true, | ||
"trailingComma": "es5", | ||
"useTabs": false, | ||
"arrowParens": "always", | ||
"bracketSpacing": true, | ||
"bracketSameLine": false | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"extends": [ | ||
"stylelint-config-standard", | ||
"stylelint-config-recess-order", | ||
"stylelint-config-prettier" | ||
], | ||
"customSyntax": "postcss-styled-syntax" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# 점메츄 | ||
|
||
## 점심 메뉴 츄천 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
컴포넌트 분리 기준: | ||
|
||
단일 책임 원칙 (Single Responsibility Principle): 컴포넌트는 한 가지 기능 또는 역할에 집중해야 한다. | ||
재사용성: 여러 곳에서 사용될 수 있도록 설계되어야 한다. | ||
가독성: 각 컴포넌트는 명확하게 구분되어야 하며, 컴포넌트의 이름과 구조가 코드를 읽기 쉽게 만들어야 합니다. | ||
|
||
좋은 상태 관리: | ||
|
||
최소한의 상태 유지: 컴포넌트가 필요 이상으로 많은 상태를 가지면 복잡성이 증가할 수 있다. | ||
상태 불변성 유지: 상태를 직접 변경하는 것이 아니라 setState를 사용하여 상태를 변경하면서 불변성을 유지해야 힌다. | ||
|
||
렌더링 효과적 관리: | ||
|
||
PureComponent 및 memoization 활용: PureComponent나 React.memo를 사용하여 불필요한 렌더링을 방지한다. | ||
|
||
Props Drilling과 해결 방법: | ||
|
||
Props Drilling: 여러 레벨의 하위 컴포넌트로 props를 전달하는 과정에서 코드가 복잡해지고 유지보수가 어려워지는 상황. | ||
Context API 사용: React의 Context API를 사용하여 전역적으로 상태를 관리하고, 필요한 컴포넌트에서 필요한 값을 가져올 수 있다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!doctype html> | ||
<html lang="ko"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>점메추 - 굶을래?</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.jsx"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"name": "menu-recommend", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "vite build", | ||
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", | ||
"preview": "vite preview", | ||
"format": "prettier --write --cache ." | ||
}, | ||
"resolutions": { | ||
"styled-components": "^5" | ||
}, | ||
"dependencies": { | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"styled-components": "^6.1.0" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.2.15", | ||
"@types/react-dom": "^18.2.7", | ||
"@vitejs/plugin-react": "^4.0.3", | ||
"eslint": "^8.53.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-prettier": "^5.0.1", | ||
"eslint-plugin-react": "^7.33.2", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-refresh": "^0.4.3", | ||
"postcss-styled-syntax": "^0.5.0", | ||
"prettier": "^3.0.3", | ||
"stylelint": "^15.11.0", | ||
"stylelint-config-prettier": "^9.0.5", | ||
"stylelint-config-recess-order": "^4.3.0", | ||
"stylelint-config-standard": "^34.0.0", | ||
"vite": "^4.4.5" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { useState } from 'react'; | ||
import Header from '@components/Header'; | ||
import MainSection from '@components/MainSection'; | ||
import GlobalStyle from '@styles/GlobalStyle'; | ||
|
||
export default function App() { | ||
const [selectOption, setSelectOption] = useState(''); | ||
const [startPick, setStartPick] = useState(false); | ||
|
||
return ( | ||
<> | ||
<GlobalStyle /> | ||
<Header | ||
selectOption={selectOption} | ||
selectOptionHandler={(selected) => { | ||
setSelectOption(selected); | ||
}} | ||
startPickHandler={(isStart) => { | ||
setStartPick(isStart); | ||
}} | ||
/> | ||
<MainSection | ||
selectOption={selectOption} | ||
startPick={startPick} | ||
selectOptionHandler={(selected) => { | ||
setSelectOption(selected); | ||
}} | ||
startPickHandler={(isStart) => { | ||
setStartPick(isStart); | ||
}} | ||
/> | ||
</> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import * as S from './style'; | ||
|
||
const Header = ({ selectOption, selectOptionHandler, startPickHandler }) => { | ||
return ( | ||
<S.HeaderStyle> | ||
<h1>🍛 오늘의 점메추 🍛</h1> | ||
{selectOption !== '' && ( | ||
<S.ReStartButton | ||
onClick={() => { | ||
selectOptionHandler(''); | ||
startPickHandler(false); | ||
}} | ||
> | ||
처음으로 | ||
</S.ReStartButton> | ||
)} | ||
</S.HeaderStyle> | ||
); | ||
}; | ||
|
||
export default Header; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import styled from 'styled-components'; | ||
|
||
const HeaderStyle = styled.header` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 시맨틱하게 잘했다 !! |
||
position: relative; | ||
width: 100%; | ||
padding: 5rem 0; | ||
font-size: 3.6rem; | ||
text-align: center; | ||
border: 1px solid #555; | ||
`; | ||
|
||
const ReStartButton = styled.button` | ||
position: absolute; | ||
top: 50%; | ||
right: 10rem; | ||
padding: 1rem 2rem; | ||
font-size: 2.4rem; | ||
border: 1px solid #555; | ||
border-radius: 1rem; | ||
transition: all 0.3s ease; | ||
transform: translateY(-50%); | ||
|
||
&:hover { | ||
background-color: #222; | ||
} | ||
`; | ||
|
||
export { HeaderStyle, ReStartButton }; |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 선택되지 않았을 때 0, 선택된 항목 순서에 따라서 1 ,2, 3 이렇게 숫자값을 준 것 같은데, 그 숫자가 각 항목을 뜻한다는걸 좀 보고 난 뒤에야 알았거든! 그래서 의미가 나타나지 않는 이런 숫자를 쓰기보다는 의미가 담긴 값(예를 들면 string)을 사용하면 좋을 것 같아! 그럼에도 나는 숫자값으로 관리를 하고 싶다면 export const SELECT_OPTION = { 이런식으로 만들어놓고 가져다 쓰는 것도 괜찮겠당. 뭔가 상수 얘기를 많이 하게 되는군 크크 |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,56 @@ | ||||||
import * as S from '../style'; | ||||||
|
||||||
const FirstChoice = ({ firstChoice, selectOptionHandler, startPickHandler, dispatchHandler }) => { | ||||||
return ( | ||||||
<> | ||||||
<S.SubTitleStyle>오늘은 어떤 종류가 먹고 싶어?</S.SubTitleStyle> | ||||||
<S.CountParagraph>1 / 3</S.CountParagraph> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이런것두 다 매직 넘붤이다 |
||||||
<S.MainSectionStyle> | ||||||
<S.ArticleStyle | ||||||
$isClicked={firstChoice === 1 ? true : false} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
이렇게만 줘도 되겠네용 ! |
||||||
onClick={() => { | ||||||
dispatchHandler('first', 1); | ||||||
}} | ||||||
> | ||||||
<a href="#">한식</a> | ||||||
</S.ArticleStyle> | ||||||
<S.ArticleStyle | ||||||
$isClicked={firstChoice === 2 ? true : false} | ||||||
onClick={() => { | ||||||
dispatchHandler('first', 2); | ||||||
}} | ||||||
> | ||||||
<a href="#">일식</a> | ||||||
</S.ArticleStyle> | ||||||
<S.ArticleStyle | ||||||
$isClicked={firstChoice === 3 ? true : false} | ||||||
onClick={() => { | ||||||
dispatchHandler('first', 3); | ||||||
}} | ||||||
> | ||||||
<a href="#">중식</a> | ||||||
</S.ArticleStyle> | ||||||
</S.MainSectionStyle> | ||||||
<S.ButtonBox> | ||||||
<S.NextButton | ||||||
onClick={() => { | ||||||
selectOptionHandler(''); | ||||||
startPickHandler(false); | ||||||
}} | ||||||
> | ||||||
이전으로 | ||||||
</S.NextButton> | ||||||
<S.NextButton | ||||||
disabled={firstChoice === 0} | ||||||
onClick={() => { | ||||||
dispatchHandler('done', 2); | ||||||
}} | ||||||
> | ||||||
다음으로 | ||||||
</S.NextButton> | ||||||
</S.ButtonBox> | ||||||
</> | ||||||
); | ||||||
}; | ||||||
|
||||||
export default FirstChoice; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import * as S from '../style'; | ||
|
||
const LastChoice = ({ thirdChoice, dispatchHandler }) => { | ||
return ( | ||
<> | ||
<S.SubTitleStyle>마지막으로 골라줘!</S.SubTitleStyle> | ||
<S.CountParagraph>3 / 3</S.CountParagraph> | ||
<S.MainSectionStyle> | ||
<S.ArticleStyle | ||
$isClicked={thirdChoice === 1 ? true : false} | ||
onClick={() => { | ||
dispatchHandler('third', 1); | ||
}} | ||
> | ||
<a href="#">국물 X</a> | ||
</S.ArticleStyle> | ||
<S.ArticleStyle | ||
$isClicked={thirdChoice === 2 ? true : false} | ||
onClick={() => { | ||
dispatchHandler('third', 2); | ||
}} | ||
> | ||
<a href="#">국물 O</a> | ||
</S.ArticleStyle> | ||
</S.MainSectionStyle> | ||
<S.ButtonBox> | ||
<S.NextButton | ||
onClick={() => { | ||
dispatchHandler('done', 2); | ||
}} | ||
> | ||
이전으로 | ||
</S.NextButton> | ||
<S.NextButton | ||
disabled={thirdChoice === 0} | ||
onClick={() => { | ||
dispatchHandler('done', 4); | ||
}} | ||
> | ||
결과보기 | ||
</S.NextButton> | ||
</S.ButtonBox> | ||
</> | ||
); | ||
}; | ||
|
||
export default LastChoice; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게만 해도 되겠다! 빈 문자열은 falsy값, 빈 문자열이 아니면 truthy 값이라서 가능합니당