-
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주차 기본/심화/생각] 로그인/회원가입 #7
base: main
Are you sure you want to change the base?
Changes from all commits
af94e1b
d555e29
9882b29
b9a4f7c
7888eee
439d85b
159a7a7
0d25d51
e985006
7f7e492
ac3f3d9
860e162
d73be2b
2caead0
a121e28
6e2a47a
49880ad
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,20 @@ | ||
module.exports = { | ||
root: true, | ||
env: { browser: true, es2020: true }, | ||
extends: [ | ||
'eslint:recommended', | ||
'plugin:react/recommended', | ||
'plugin:react/jsx-runtime', | ||
'plugin:react-hooks/recommended', | ||
], | ||
ignorePatterns: ['dist', '.eslintrc.cjs'], | ||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, | ||
settings: { react: { version: '18.2' } }, | ||
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,27 @@ | ||
# 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? | ||
|
||
# dotenv environment variable files | ||
.env |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
API 통신에 대하여 | ||
|
||
- 로딩 / 에러 처리를 하는 방법에는 어떤 것들이 있을까? | ||
- 로딩: | ||
- 로딩 스피너 사용 | ||
- 사용자에게 메시지 띄우기(ex.로딩중입니다..조금만 기다려주세요 등등) | ||
- 에러: | ||
- input 에러일때: 사용자에게 메시지 띄우기(ex. 이미 사용중인 아이디입니다) | ||
- 에러가 안 뜨는 페이지로 보내고 메시지 띄우기(ex. 일시적 에러가 발생했습니다. 잠시 후 다시 시도해주세요 등등) | ||
- 패칭 라이브러리란 무엇이고 어떤 것들이 있을까? | ||
- "네트워크 요청을 관리하고 처리하기 위한 도구"라고 한다 | ||
- axios, fetch,.. | ||
- (사실 자바스크립트에는 fetch api가 존재하지만, 더 많은 기능을 지원하기에 개발자들은 서버 통신에 보다 편리한 axios를 선호한다.라네요) | ||
- 패칭 라이브러리를 쓰는 이유는 무엇일까? | ||
- 1. 간편하다! 이미 필요한 코드들을 응집해서 만들어둔 라이브러리로 그것을 사용하기만 하면 되기 때문에. 비동기처리에도 효과적인 대응이 가능하다 | ||
- 2. 이건 잘 몰라서 찾아봤는데 인터셉터 및 설정 부분에서 패칭 라이브러리는 요청과 응답을 가로채고 수정할 수 있는 인터셉터를 제공하여 특정 요구사항에 맞게 설정할 수 있다네요.. |
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 |
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</title> | ||
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. 요기도 프로젝트의 특성에 맞게 바궈줘보기 ! |
||
</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,29 @@ | ||
{ | ||
"name": "package", | ||
"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" | ||
}, | ||
"dependencies": { | ||
"axios": "^1.6.2", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-router-dom": "^6.19.0", | ||
"styled-components": "^6.1.1" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.2.37", | ||
"@types/react-dom": "^18.2.15", | ||
"@vitejs/plugin-react": "^4.2.0", | ||
"eslint": "^8.53.0", | ||
"eslint-plugin-react": "^7.33.2", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-refresh": "^0.4.4", | ||
"vite": "^5.0.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#root { | ||
max-width: 1280px; | ||
margin: 0 auto; | ||
padding: 2rem; | ||
text-align: center; | ||
} | ||
|
||
.logo { | ||
height: 6em; | ||
padding: 1.5em; | ||
will-change: filter; | ||
transition: filter 300ms; | ||
} | ||
.logo:hover { | ||
filter: drop-shadow(0 0 2em #646cffaa); | ||
} | ||
.logo.react:hover { | ||
filter: drop-shadow(0 0 2em #61dafbaa); | ||
} | ||
|
||
@keyframes logo-spin { | ||
from { | ||
transform: rotate(0deg); | ||
} | ||
to { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
|
||
@media (prefers-reduced-motion: no-preference) { | ||
a:nth-of-type(2) .logo { | ||
animation: logo-spin infinite 20s linear; | ||
} | ||
} | ||
|
||
.card { | ||
padding: 2em; | ||
} | ||
|
||
.read-the-docs { | ||
color: #888; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Route, BrowserRouter, Routes } from "react-router-dom"; | ||
import "./App.css"; | ||
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. 요거 안쓰는거 아닌가용? |
||
import Login from "./Login"; | ||
import SignUp from "./Signup"; | ||
import MyPage from "./Mypage"; | ||
|
||
function App() { | ||
return ( | ||
<BrowserRouter> | ||
<Routes> | ||
<Route path="/login" element={<Login />} /> | ||
<Route path="/signup" element={<SignUp />} /> | ||
<Route path="/mypage/:userId" element={<MyPage />} /> | ||
</Routes> | ||
</BrowserRouter> | ||
); | ||
} | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,118 @@ | ||||||||||||||||||
import { useState, useEffect } from "react"; | ||||||||||||||||||
import styled from "styled-components"; | ||||||||||||||||||
import "./App.css"; | ||||||||||||||||||
import axios from "axios"; | ||||||||||||||||||
import { Link, Navigate, useNavigate } from "react-router-dom"; | ||||||||||||||||||
import { createPortal } from "react-dom"; | ||||||||||||||||||
import { | ||||||||||||||||||
MainBox, | ||||||||||||||||||
Header, | ||||||||||||||||||
Section, | ||||||||||||||||||
Sections, | ||||||||||||||||||
SectionInput, | ||||||||||||||||||
SectionTitle, | ||||||||||||||||||
} from "./style"; | ||||||||||||||||||
|
||||||||||||||||||
export default function Login() { | ||||||||||||||||||
const [username, setUsername] = useState(""); | ||||||||||||||||||
const [password, setPassword] = useState(""); | ||||||||||||||||||
|
||||||||||||||||||
const [showToast, setShowToast] = useState(false); | ||||||||||||||||||
const [toastMessage, setToastMessage] = useState(""); | ||||||||||||||||||
|
||||||||||||||||||
const navigate = useNavigate(); | ||||||||||||||||||
|
||||||||||||||||||
const handleUserName = (e) => { | ||||||||||||||||||
setUsername(e.target.value); | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
const handlePassword = (e) => { | ||||||||||||||||||
setPassword(e.target.value); | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
const handleLogin = () => { | ||||||||||||||||||
axios | ||||||||||||||||||
.post(import.meta.env.VITE_BASE_URL + "/api/v1/members/sign-in", { | ||||||||||||||||||
username: username, | ||||||||||||||||||
password: password, | ||||||||||||||||||
}) | ||||||||||||||||||
Comment on lines
+35
to
+38
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
템플릿 리터럴과 단축 프로퍼티 사용하기! |
||||||||||||||||||
.then((response) => { | ||||||||||||||||||
navigate(`/mypage/${response.data.id}`); | ||||||||||||||||||
}) | ||||||||||||||||||
.catch((error) => { | ||||||||||||||||||
setToastMessage(error.response.data.message); | ||||||||||||||||||
setShowToast(true); | ||||||||||||||||||
}); | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
useEffect(() => { | ||||||||||||||||||
// 3초 후 사라짐 | ||||||||||||||||||
const timer = setTimeout(() => { | ||||||||||||||||||
setShowToast(false); | ||||||||||||||||||
}, 3000); | ||||||||||||||||||
|
||||||||||||||||||
return () => clearTimeout(timer); | ||||||||||||||||||
}, [showToast]); | ||||||||||||||||||
|
||||||||||||||||||
const toastElement = showToast ? ( | ||||||||||||||||||
<ToastContainer>{toastMessage}</ToastContainer> | ||||||||||||||||||
) : null; | ||||||||||||||||||
|
||||||||||||||||||
return ( | ||||||||||||||||||
<MainBox> | ||||||||||||||||||
<Header>Login</Header> | ||||||||||||||||||
<Sections> | ||||||||||||||||||
<Section> | ||||||||||||||||||
<SectionTitle>ID</SectionTitle> | ||||||||||||||||||
<SectionInput | ||||||||||||||||||
value={username} | ||||||||||||||||||
onChange={handleUserName} | ||||||||||||||||||
placeholder="아이디를 입력해주세요" | ||||||||||||||||||
/> | ||||||||||||||||||
</Section> | ||||||||||||||||||
<Section> | ||||||||||||||||||
<SectionTitle>PASSWORD</SectionTitle> | ||||||||||||||||||
<SectionInput | ||||||||||||||||||
value={password} | ||||||||||||||||||
onChange={handlePassword} | ||||||||||||||||||
placeholder="비밀번호를 입력해주세요" | ||||||||||||||||||
/> | ||||||||||||||||||
</Section> | ||||||||||||||||||
Comment on lines
+65
to
+80
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, password 같은 문자열 값을 넣어줬어. |
||||||||||||||||||
</Sections> | ||||||||||||||||||
|
||||||||||||||||||
<Button | ||||||||||||||||||
type="submit" | ||||||||||||||||||
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. 헉 야무지게 설정해줬당 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. 잊지 않고 type 설정해주기 좋다! 그런데 button의 type중에 submit은 태그에서 form data가 제출되는 버튼임을 명시하기 위함이라서type="button' 이 맞답니당
|
||||||||||||||||||
onClick={() => { | ||||||||||||||||||
handleLogin(); | ||||||||||||||||||
}} | ||||||||||||||||||
> | ||||||||||||||||||
로그인 | ||||||||||||||||||
</Button> | ||||||||||||||||||
<Link to="/signup"> | ||||||||||||||||||
<Button>회원가입</Button> | ||||||||||||||||||
</Link> | ||||||||||||||||||
{createPortal(toastElement, document.body)} | ||||||||||||||||||
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. 모달을 띄워주는 부분도 로그인과는 역할이 다른 부분이라 컴포넌트 분리를 해주는게 좋을 것 같아! |
||||||||||||||||||
</MainBox> | ||||||||||||||||||
); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
const Button = styled.button` | ||||||||||||||||||
width: 80%; | ||||||||||||||||||
height: 3rem; | ||||||||||||||||||
|
||||||||||||||||||
margin: 0.5rem auto; | ||||||||||||||||||
border: 1px solid black; | ||||||||||||||||||
`; | ||||||||||||||||||
|
||||||||||||||||||
const ToastContainer = styled.div` | ||||||||||||||||||
position: fixed; | ||||||||||||||||||
bottom: 15rem; | ||||||||||||||||||
left: 50%; | ||||||||||||||||||
transform: translateX(-50%); | ||||||||||||||||||
|
||||||||||||||||||
padding: 1rem; | ||||||||||||||||||
|
||||||||||||||||||
background-color: gray; | ||||||||||||||||||
color: white; | ||||||||||||||||||
border-radius: 0.5rem; | ||||||||||||||||||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { useEffect, useState } from "react"; | ||
import styled from "styled-components"; | ||
import "./App.css"; | ||
import axios from "axios"; | ||
import { useParams, Link } from "react-router-dom"; | ||
import { MainBox, Header } from "./style"; | ||
|
||
export default function MyPage() { | ||
let { userId } = useParams(); | ||
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 쓰면 안되는 이유가 있나?? 아니면 바뀌어야하는 값이니까 혹시몰라서 let 쓴거야?? 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 [username, setUsername] = useState(""); | ||
const [nickname, setNickname] = useState(""); | ||
|
||
useEffect(() => { | ||
const fetchUserInfo = async () => { | ||
try { | ||
const response = await axios.get( | ||
import.meta.env.VITE_BASE_URL + `/api/v1/members/${userId}` | ||
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. 얘도 매번 타이핑하기 귀찮을텐데 따로 빼서 관리해보쟈 |
||
); | ||
setUsername(response.data.username); | ||
setNickname(response.data.nickname); | ||
} catch (error) { | ||
console.log(error.message); | ||
} | ||
}; | ||
fetchUserInfo(); | ||
}); | ||
return ( | ||
<MainBox> | ||
<Header>MY PAGE</Header> | ||
<Infos> | ||
<ProfileImg src="/profile.JPG" /> | ||
<InfoText> | ||
<Info>ID : {username}</Info> | ||
<Info>NICKNAME : {nickname}</Info> | ||
</InfoText> | ||
</Infos> | ||
<Link to="../../login"> | ||
<button>로그아웃</button> | ||
</Link> | ||
</MainBox> | ||
); | ||
} | ||
|
||
const Infos = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
|
||
width: 100%; | ||
height: 50%; | ||
`; | ||
|
||
const InfoText = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
`; | ||
|
||
const ProfileImg = styled.img` | ||
width: 5rem; | ||
height: 5rem; | ||
|
||
border-radius: 50%; | ||
border: 1px solid black; | ||
`; | ||
|
||
const Info = styled.div` | ||
height: 3rem; | ||
width: 10rem; | ||
padding: 0 1rem; | ||
|
||
text-align: left; | ||
font-weight: bold; | ||
line-height: 3rem; | ||
`; |
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로 바꾸는거 같이 습관들여보자 ㅋㅋㅋ 나도 내 습관 고쳐볼게