-
Notifications
You must be signed in to change notification settings - Fork 0
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주차/기본/공유과제] #5
base: main
Are you sure you want to change the base?
Changes from 24 commits
d607042
9599a78
2a3acb0
1ac0693
2bbb7be
f99fc31
87d86dc
7a5990b
866198e
b19b79e
57ddbee
fdb77ea
2fe123e
3ec0dc0
df21b75
8149675
1a36974
211c05f
affe0ba
d09ff7d
4894484
4bf28e6
a897f59
3a93f74
223ce23
05c050a
3296409
cc74c77
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,18 @@ | ||
module.exports = { | ||
root: true, | ||
env: { browser: true, es2020: true }, | ||
extends: [ | ||
'eslint:recommended', | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:react-hooks/recommended', | ||
], | ||
ignorePatterns: ['dist', '.eslintrc.cjs'], | ||
parser: '@typescript-eslint/parser', | ||
plugins: ['react-refresh'], | ||
rules: { | ||
'react-refresh/only-export-components': [ | ||
'warn', | ||
{ allowConstantExport: true }, | ||
], | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# 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? | ||
.env |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# 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 { | ||
// other rules... | ||
parserOptions: { | ||
ecmaVersion: 'latest', | ||
sourceType: 'module', | ||
project: ['./tsconfig.json', './tsconfig.node.json'], | ||
tsconfigRootDir: __dirname, | ||
}, | ||
} | ||
``` | ||
|
||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` | ||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` | ||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!DOCTYPE html> | ||
<html lang="ko"> | ||
<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,31 @@ | ||
{ | ||
"name": "week4", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc && vite build", | ||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"axios": "^1.6.8", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-router-dom": "^6.23.0", | ||
"styled-components": "^6.1.10" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.2.66", | ||
"@types/react-dom": "^18.2.22", | ||
"@typescript-eslint/eslint-plugin": "^7.2.0", | ||
"@typescript-eslint/parser": "^7.2.0", | ||
"@vitejs/plugin-react-swc": "^3.5.0", | ||
"eslint": "^8.57.0", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-refresh": "^0.4.6", | ||
"typescript": "^5.2.2", | ||
"vite": "^5.2.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. public 폴더 안에 img 폴더 가 있는거 같은데, 이 폴더를 assets에 옮기면 좋을 거 같아요! |
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. 이 파일은 지워도 될 거 같아요..!! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import Router from "./Router"; | ||
|
||
function App() { | ||
return ( | ||
<> | ||
<Router /> | ||
</> | ||
); | ||
} | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { BrowserRouter, Route, Routes } from "react-router-dom"; | ||
import Join from "./pages/Join"; | ||
import Login from "./pages/Login"; | ||
import Main from "./pages/Main"; | ||
import My from "./pages/My"; | ||
|
||
const Router = () => { | ||
return ( | ||
<BrowserRouter> | ||
<Routes> | ||
<Route path="/login" element={<Login />}></Route> | ||
<Route path="/join" element={<Join />}></Route> | ||
<Route path="/main" element={<Main />}></Route> | ||
<Route path="/my/:memberId" element={<My />}></Route> | ||
</Routes> | ||
</BrowserRouter> | ||
Comment on lines
+9
to
+16
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. 오 마이갓... 완벽한 라우팅 최고입니다, 다음에는 path='/'일 때, 그리고 라우팅이 없는 url로 접속했을 때에는 어떤 화면을 보여줄지에 대한것도 생각해보시면 좋을것 같아요! 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. 저도 이번에는 라우팅이 없는 url은 신경쓰지 않았는데 확실히 신경쓰는게 좋을 것 같아요! 좋은 제안 감사합니다 |
||
); | ||
}; | ||
|
||
export default Router; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from "react"; | ||
import ReactDOM from "react-dom/client"; | ||
import App from "./App.tsx"; | ||
|
||
ReactDOM.createRoot(document.getElementById("root")!).render( | ||
<React.StrictMode> | ||
<App /> | ||
</React.StrictMode> | ||
); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,102 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
import { useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||
import styled from "styled-components"; | ||||||||||||||||||||||||||||||||||||||||||||||
import axios, { AxiosError } from "axios"; | ||||||||||||||||||||||||||||||||||||||||||||||
import { useNavigate } from "react-router-dom"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
function Join() { | ||||||||||||||||||||||||||||||||||||||||||||||
const [userId, setUserId] = useState(""); | ||||||||||||||||||||||||||||||||||||||||||||||
const [userPw, setUserPw] = useState(""); | ||||||||||||||||||||||||||||||||||||||||||||||
const [userNickName, setNickName] = useState(""); | ||||||||||||||||||||||||||||||||||||||||||||||
const [userPhoneNumber, setPhoneNumber] = useState(""); | ||||||||||||||||||||||||||||||||||||||||||||||
const navigate = useNavigate(); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const submitForm = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||
const postJoinData = await axios.post( | ||||||||||||||||||||||||||||||||||||||||||||||
`${import.meta.env.VITE_APP_BASE_URL}/member/join`, | ||||||||||||||||||||||||||||||||||||||||||||||
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. wow... env 사용을 자유자재로 하시는군요... api 주소같이 외부로 노출되면 안되는 부분을 .evn를 사용해서 처리하신게 너무 좋네요~ 다음 프로젝트하실 때도 이런 습관을 들이면 좋을것 같아요 |
||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||
authenticationId: userId, | ||||||||||||||||||||||||||||||||||||||||||||||
password: userPw, | ||||||||||||||||||||||||||||||||||||||||||||||
nickname: userNickName, | ||||||||||||||||||||||||||||||||||||||||||||||
phone: userPhoneNumber, | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||
console.log(postJoinData); | ||||||||||||||||||||||||||||||||||||||||||||||
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. 개발중에 확인을 위해서 사용한 console.log() 성능이나 보안적인 측면에서 지워주는게 좋다고 해요! 다음에는 확인후에 지워서 git에 올리는 걸 추천해드립니다! |
||||||||||||||||||||||||||||||||||||||||||||||
alert("웰컴!"); | ||||||||||||||||||||||||||||||||||||||||||||||
navigate("/login"); | ||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||
if (error instanceof AxiosError) { | ||||||||||||||||||||||||||||||||||||||||||||||
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. 오 마이 굿니스... 에러가 AxiosError객체의 인스턴스인것을 명시해줌으로서 타입에러를 해결하셨군요.. 최고입니다 |
||||||||||||||||||||||||||||||||||||||||||||||
alert(error.response?.data.message); | ||||||||||||||||||||||||||||||||||||||||||||||
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. error.response가 있을 때만 메세지를 출력하게 하셨군요 저는 if문에서 따로 확인을 했었는데 이렇게 alet에서 확인하는 것도 좋은 방법같네요 배워갑니당! |
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
console.log(error); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||
<> | ||||||||||||||||||||||||||||||||||||||||||||||
<JoinWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||
<JoinContainer> | ||||||||||||||||||||||||||||||||||||||||||||||
<span>회원가입 페이지</span> | ||||||||||||||||||||||||||||||||||||||||||||||
<p>아이디</p> | ||||||||||||||||||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||||||||||||||||||||||
type="text" | ||||||||||||||||||||||||||||||||||||||||||||||
value={userId} | ||||||||||||||||||||||||||||||||||||||||||||||
onChange={(e) => setUserId(e.target.value)} | ||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+41
to
+48
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
|
||||||||||||||||||||||||||||||||||||||||||||||
<p>비밀번호</p> | ||||||||||||||||||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||||||||||||||||||||||
type="text" | ||||||||||||||||||||||||||||||||||||||||||||||
value={userPw} | ||||||||||||||||||||||||||||||||||||||||||||||
onChange={(e) => setUserPw(e.target.value)} | ||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||
<p> | ||||||||||||||||||||||||||||||||||||||||||||||
비밀번호가 형식(최소 8글자 이상, 숫자, 문자(a-z, A-Z), 특수문자 | ||||||||||||||||||||||||||||||||||||||||||||||
포함) | ||||||||||||||||||||||||||||||||||||||||||||||
</p> | ||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||
<p>닉네임</p> | ||||||||||||||||||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||||||||||||||||||||||
type="text" | ||||||||||||||||||||||||||||||||||||||||||||||
value={userNickName} | ||||||||||||||||||||||||||||||||||||||||||||||
onChange={(e) => setNickName(e.target.value)} | ||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||
<p>전화번호</p> | ||||||||||||||||||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||||||||||||||||||||||
type="string" | ||||||||||||||||||||||||||||||||||||||||||||||
value={userPhoneNumber} | ||||||||||||||||||||||||||||||||||||||||||||||
onChange={(e) => setPhoneNumber(e.target.value)} | ||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||
<p>전화번호가 형식(010-****-****)</p> | ||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
<button type="button" onClick={submitForm}> | ||||||||||||||||||||||||||||||||||||||||||||||
회원가입 | ||||||||||||||||||||||||||||||||||||||||||||||
</button> | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+79
to
+81
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. 버튼 부분도 반복되고 있으니 공통 컴포넌트로 분리해서 적용하면 좋을 거 같아요!! |
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
<button onClick={() => navigate(-1)}>뒤로가기</button> | ||||||||||||||||||||||||||||||||||||||||||||||
</JoinContainer> | ||||||||||||||||||||||||||||||||||||||||||||||
</JoinWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
export default Join; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const JoinWrapper = styled.div` | ||||||||||||||||||||||||||||||||||||||||||||||
display: flex; | ||||||||||||||||||||||||||||||||||||||||||||||
justify-content: center; | ||||||||||||||||||||||||||||||||||||||||||||||
align-items: center; | ||||||||||||||||||||||||||||||||||||||||||||||
background-color: #f5dad2; | ||||||||||||||||||||||||||||||||||||||||||||||
font-size: 2rem; | ||||||||||||||||||||||||||||||||||||||||||||||
`; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const JoinContainer = styled.div` | ||||||||||||||||||||||||||||||||||||||||||||||
width: 20rem; | ||||||||||||||||||||||||||||||||||||||||||||||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { useState } from "react"; | ||
import styled from "styled-components"; | ||
import axios from "axios"; | ||
import img1 from "../../public/img/포챠코.png"; | ||
import { useNavigate } from "react-router-dom"; | ||
|
||
function Login() { | ||
const [userId, setUserId] = useState(""); | ||
const [userPw, setUserPw] = useState(""); | ||
const [uniqueId, setUniqueId] = useState(""); | ||
|
||
const navigate = useNavigate(); | ||
|
||
const handleClickLogin = async () => { | ||
try { | ||
const postData = await axios.post( | ||
`${import.meta.env.VITE_APP_BASE_URL}/member/login`, | ||
{ | ||
authenticationId: userId, | ||
password: userPw, | ||
} | ||
); | ||
const memberId = postData.headers.location; | ||
navigate(`/my/${memberId}`); | ||
|
||
setUniqueId(uniqueId); | ||
// console.log(postData); | ||
// console.log(memberId); | ||
} catch (error) { | ||
alert("아이디,비밀번호를 입력하세요"); | ||
console.log(error); | ||
} | ||
}; | ||
Comment on lines
+14
to
+33
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. 로그인 로직 너무 깔끔하고 좋은데요~~ axios를 잘 사용하시는걸로 봐서 다음에는 axios instance를 활용해보는것도 좋은 경험이 될 것 같아요! 합세 때 해봅시다!! |
||
|
||
return ( | ||
<> | ||
<LoginWrapper> | ||
<LoginContainer> | ||
<span>로그인</span> | ||
<img src={img1} alt="포챠코이미지" width="150rem" /> | ||
<p>아이디</p> | ||
<div> | ||
<input | ||
type="text" | ||
value={userId} | ||
onChange={(e) => setUserId(e.target.value)} | ||
/> | ||
</div> | ||
Comment on lines
+41
to
+48
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. 요기도 이전에 언급한 부분이랑 형식이 동일하게 반복되는데 컴포넌트 폴더를 하나 만들어서 분리해두면 좋을것 같아유 |
||
<p>비밀번호</p> | ||
<div> | ||
<input | ||
type="text" | ||
value={userPw} | ||
onChange={(e) => setUserPw(e.target.value)} | ||
/> | ||
</div> | ||
|
||
<button type="button" onClick={handleClickLogin}> | ||
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. 버튼도 반복해서 사용한다면 버튼 컴포넌트를 만들어서 이를 사용하는 것도 추천해드립니다! |
||
로그인 | ||
</button> | ||
|
||
<button type="button" onClick={() => navigate("/join")}> | ||
회원가입 | ||
</button> | ||
</LoginContainer> | ||
</LoginWrapper> | ||
</> | ||
); | ||
} | ||
|
||
export default Login; | ||
|
||
const LoginWrapper = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
background-color: #f5dad2; | ||
font-size: 2rem; | ||
`; | ||
|
||
const LoginContainer = styled.div` | ||
width: 10rem; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Link } from "react-router-dom"; | ||
import img2 from "../../public/img/피짱즈.png"; | ||
import styled from "styled-components"; | ||
|
||
const Main = () => { | ||
return ( | ||
<MainWrapper> | ||
<MainContainer> | ||
<img src={img2} alt="피짱즈이미지" width="300rem" /> | ||
<Link to="/my/:memberId"> | ||
<button type="button">내정보</button> | ||
</Link> | ||
Comment on lines
+10
to
+12
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. 저는 useNavigate를 사용했는데, Link를 사용하셨군요! 이 부분에서는 클릭했을 때 아무런 조건없이 해당 url로 이동해야하니 적절한 사용이되겠네요 하나 배워갑니다 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. 저도 link를 사용할 생각은 못했는데 배워갑니다! |
||
<Link to="/join"> | ||
<button type="button">회원가입</button> | ||
</Link> | ||
</MainContainer> | ||
</MainWrapper> | ||
); | ||
}; | ||
|
||
export default Main; | ||
|
||
const MainWrapper = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
background-color: #f5dad2; | ||
font-size: 2rem; | ||
`; | ||
|
||
const MainContainer = styled.div` | ||
width: 20rem; | ||
`; |
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.
ko로 바꿔주는 꼼꼼함 굳굳!!