-
Notifications
You must be signed in to change notification settings - Fork 6
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
조민영 과제 제출 합니다 #4
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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,50 @@ | ||
# React + TypeScript + 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 | ||
|
||
## Expanding the ESLint configuration | ||
|
||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: | ||
|
||
- Configure the top-level `parserOptions` property like this: | ||
|
||
```js | ||
export default tseslint.config({ | ||
languageOptions: { | ||
// other options... | ||
parserOptions: { | ||
project: ['./tsconfig.node.json', './tsconfig.app.json'], | ||
tsconfigRootDir: import.meta.dirname, | ||
}, | ||
}, | ||
}) | ||
``` | ||
|
||
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` | ||
- Optionally add `...tseslint.configs.stylisticTypeChecked` | ||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: | ||
|
||
```js | ||
// eslint.config.js | ||
import react from 'eslint-plugin-react' | ||
|
||
export default tseslint.config({ | ||
// Set the react version | ||
settings: { react: { version: '18.3' } }, | ||
plugins: { | ||
// Add the react plugin | ||
react, | ||
}, | ||
rules: { | ||
// other rules... | ||
// Enable its recommended rules | ||
...react.configs.recommended.rules, | ||
...react.configs['jsx-runtime'].rules, | ||
}, | ||
}) | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import js from '@eslint/js' | ||
import globals from 'globals' | ||
import reactHooks from 'eslint-plugin-react-hooks' | ||
import reactRefresh from 'eslint-plugin-react-refresh' | ||
import tseslint from 'typescript-eslint' | ||
|
||
export default tseslint.config( | ||
{ ignores: ['dist'] }, | ||
{ | ||
extends: [js.configs.recommended, ...tseslint.configs.recommended], | ||
files: ['**/*.{ts,tsx}'], | ||
languageOptions: { | ||
ecmaVersion: 2020, | ||
globals: globals.browser, | ||
}, | ||
plugins: { | ||
'react-hooks': reactHooks, | ||
'react-refresh': reactRefresh, | ||
}, | ||
rules: { | ||
...reactHooks.configs.recommended.rules, | ||
'react-refresh/only-export-components': [ | ||
'warn', | ||
{ allowConstantExport: true }, | ||
], | ||
}, | ||
}, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!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 + TS</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.tsx"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"name": "vite-project", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc -b && vite build", | ||
"lint": "eslint .", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"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-swc": "^3.5.0", | ||
"eslint": "^9.13.0", | ||
"eslint-plugin-react-hooks": "^5.0.0", | ||
"eslint-plugin-react-refresh": "^0.4.14", | ||
"globals": "^15.11.0", | ||
"typescript": "~5.6.2", | ||
"typescript-eslint": "^8.11.0", | ||
"vite": "^5.4.10" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#root { | ||
max-width: 1280px; | ||
margin: 0 auto; | ||
padding: 2rem; | ||
text-align: center; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import TodoTable from "./TodoTable"; | ||
import "./App.css"; | ||
|
||
function App() { | ||
return( | ||
<TodoTable/> | ||
); | ||
} | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
.container{ | ||
width: 400px; | ||
height:600px; | ||
box-shadow: 0px 2px 5px #c3c3c3 | ||
} | ||
.top{ | ||
display:flex; | ||
align-items: center; | ||
justify-content: center; | ||
height:50px; | ||
font-size:25px; | ||
font-weight: 540; | ||
color:rgba(102, 140, 255); | ||
border-bottom: 2px solid #eaeaea; | ||
|
||
} | ||
|
||
.mid{ | ||
padding-left: 10px; | ||
height: 500px; | ||
font-size:14px; | ||
color:#686767; | ||
border-bottom: 2px solid #eaeaea; | ||
} | ||
|
||
.place{ | ||
display:flex; | ||
align-items: flex-start; | ||
border:1px solid white; | ||
width:300px; | ||
height:30px; | ||
|
||
} | ||
|
||
.bottom{ | ||
display:flex; | ||
align-items: center; | ||
justify-content: space-around; | ||
height:50px; | ||
font-size: 12px; | ||
color:rgba(102, 140, 255); | ||
} | ||
|
||
.bottom button{ | ||
font-size: 12px; | ||
color:rgba(102, 140, 255); | ||
background-color: white; | ||
} | ||
|
||
|
||
table{ | ||
display:flex; | ||
align-items:flex-start; | ||
flex-direction: column; | ||
color:rgba(102, 140, 255); | ||
} | ||
|
||
.d{ | ||
font-size: 14px; | ||
color:rgba(102, 140, 255); | ||
margin-left: 80px; | ||
} | ||
|
||
input[type="checkbox"] { | ||
width: 1rem; | ||
height: 1rem; | ||
border-radius: 50%; | ||
border: 1px solid #c3c3c3; | ||
appearance: none; | ||
cursor: pointer; | ||
transition: background 0.2s; | ||
} | ||
|
||
input[type="checkbox"]:checked { | ||
background:rgba(102, 140, 255); | ||
border: none; | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-expressions */ | ||
import "./Todo.css"; | ||
import { useState } from "react"; | ||
|
||
//1. 인풋으로 입력한 내용이 todoText로 들어가야함--함수 연결해서 바뀐 값을 배열에 추가하fail.useState하기 | ||
//2. 속성과 체크박스 연결시키기--useState | ||
//3. sum--useState그리고 어케 연결? | ||
//4. 체크박스 모양 바꾸기--이건 이지 | ||
//5. 삭제 버튼을 계속 옆에 띄우는 법?--걍 넣어벌임 | ||
//6. 컴포넌트를 어떻게 쪼개지?--쪼개지말자.. | ||
let indexT = 1; | ||
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. 리액트에서는 관리해야하는 값에 대해 state라는 개념을 사용합니다. |
||
function TodoTable() { | ||
type Todos = { Id: number; todoText: string; isDone: boolean }; | ||
const [Todo, setTodo] = useState<Todos[]>([]); | ||
const [todoText, setTodoText] = useState(""); | ||
const tdList = Todo.map((Todo) => ( | ||
<tr key={Todo.Id}> | ||
<td> | ||
<label htmlFor="chBox"> | ||
<input | ||
type="checkbox" | ||
onChange={() => isitDone(Todo.Id)} | ||
checked={Todo.isDone} | ||
value={Todo.Id} | ||
/> | ||
</label> | ||
</td> | ||
<td> | ||
<span id="span">{Todo.todoText}</span> | ||
</td> | ||
<td> | ||
<button onClick={() => decrease(Todo.Id)} value={Todo.Id} className="d"> | ||
삭제 | ||
</button> | ||
</td> | ||
</tr> | ||
)); | ||
Comment on lines
+17
to
+37
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. table로 작성하신 이유가 뭔지 알려주세요! |
||
|
||
const [sum, setSum] = useState(0); | ||
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. 훅들은 최상위에 작성하는 것이 규칙입니다. |
||
const increase = () => { | ||
setSum(sum + 1); | ||
}; | ||
const decrease = (id) => { | ||
d(id); | ||
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. 함수 이름을 의미있게 작성해보는 습관을 가져볼까요? |
||
setSum(sum - 1); | ||
if (sum == 0) { | ||
setSum(0); | ||
} | ||
}; | ||
const d = (id) => { | ||
setTodo(Todo.filter((t) => t.Id !== id)); | ||
}; | ||
const inputTodo = () => { | ||
if (todoText == "") { | ||
alert("등록할 일정을 입력해주세요!"); | ||
} else { | ||
const newTodo: Todos = { | ||
Id: indexT, | ||
todoText: todoText, | ||
isDone: false, | ||
}; | ||
setTodo([...Todo, newTodo]); | ||
increase(); | ||
indexT += 1; | ||
setTodoText(""); | ||
Comment on lines
+57
to
+65
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. id는 "관리해야하는 값"에 속하기 때문에 state로 관리를 하셔야 합니다. |
||
} | ||
}; | ||
Comment on lines
+54
to
+67
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. 공백검사가 되지 않네요 또한 early return에 대해 알아보시고 early return과 if else의 차이는 무엇일지 공부해보세요! |
||
|
||
const isitDone = (id) => { | ||
setTodo( | ||
Todo.map((todo) => | ||
todo.Id === id ? { ...todo, isDone: !todo.isDone } : todo | ||
) | ||
); | ||
|
||
const filterSum = Todo.filter((todo) => todo.isDone == true); | ||
setSum(filterSum.length); | ||
Todo.map((todo) => (todo.isDone == false ? strikeLine() : nonStrike())); | ||
}; | ||
|
||
const strikeLine = () => { | ||
const c = document.getElementById("span"); | ||
c.style.textDecoration = "line-through"; | ||
}; | ||
|
||
const nonStrike = () => { | ||
const c = document.getElementById("span"); | ||
c.style.textDecoration = ""; | ||
}; | ||
Comment on lines
+76
to
+89
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. css를 적용하기 위해 함수를 작성하신 것 같은데 react에서는 직접 dom을 조작해서 스타일을 하지 않습니다. 실제로 적용도 되지 않는 것 같아보이고요. 어떤 상황에 스타일을 적용해야한다면 className에 특정 조건에 이 스타일을 적용해라라는 삼항연산자를 사용할 수 있어요! |
||
return ( | ||
<div className="container"> | ||
<div className="top"> | ||
<p>TodoList</p> | ||
</div> | ||
<div className="mid"> | ||
<input | ||
className="place" | ||
type="text" | ||
value={todoText} | ||
onChange={(t) => setTodoText(t.target.value)} | ||
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. 여기서 t가 무엇인가요? t가 하는 역할이 뭐고 이렇게 작성하신 이유를 알려주세요. |
||
name="todoText" | ||
placeholder="오늘의 할 일을 추가해보세요!" | ||
/> | ||
<table>{tdList}</table> | ||
</div> | ||
<div className="bottom"> | ||
<p>오늘의 할 일 {sum}</p> | ||
<button onClick={inputTodo}>추가하기</button> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default TodoTable; |
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.
과제를 제출할 땐 불필요한 주석은 제거해주세요.