-
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
[4주차 기본/심화/공유 과제] API 통신 #6
base: main
Are you sure you want to change the base?
Changes from all commits
b9fad10
ad30e16
cf5d5a7
962d526
f6acbd4
65021b0
0ac10cd
8c2d14a
037ed77
fee5234
32fc85c
bfe7236
afb0c12
4c4de71
a00c08a
96bb3fe
b633c39
48af8cb
c7a315c
c7a0921
b9744b8
deefd42
571e9df
fa70bc4
3546329
5925bf6
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,3 @@ | ||
{ | ||
"type": "module" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
VITE_BASE_URL = "http://211.188.53.75:8080" | ||
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? | ||
|
||
.env | ||
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. p2: 오홍 위에 엔브가 올라와있다고 코리 남겼는데,
|
||
|
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"> | ||
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. p4: HTML의 언어 속성 부분 사소한 부분이지만 저두 맨날 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,33 @@ | ||
{ | ||
"name": "my-project", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc -b && vite build", | ||
"lint": "eslint .", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"@emotion/react": "^11.13.3", | ||
"axios": "^1.7.7", | ||
"react": "^18.3.1", | ||
"react-dom": "^18.3.1", | ||
"react-icons": "^5.3.0", | ||
"react-router-dom": "^6.28.0" | ||
}, | ||
"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,30 @@ | ||
import { createBrowserRouter, RouterProvider } from "react-router-dom"; | ||
|
||
import LoginPage from "./pages/loginPage/LoginPage"; | ||
import SignUpPage from "./pages/signupPage/SignUpPage"; | ||
import MyPage from "./pages/myPage/MyPage"; | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
path: "/", | ||
element: <LoginPage></LoginPage>, | ||
}, | ||
{ | ||
path: "/signup", | ||
element: <SignUpPage></SignUpPage>, | ||
}, | ||
{ | ||
path: "/mypage", | ||
element: <MyPage></MyPage>, | ||
Comment on lines
+9
to
+18
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. p2 : 컴포넌트에 |
||
}, | ||
]); | ||
|
||
function App() { | ||
return ( | ||
<> | ||
<RouterProvider router={router}></RouterProvider> | ||
</> | ||
); | ||
} | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** @jsxImportSource @emotion/react */ | ||
import { mypageInput } from "../pages/myPage/MyPage.style"; | ||
import Button from "./common/Button/Button"; | ||
import updateUserData from "../libs/apis/updateUserData"; | ||
import { useState } from "react"; | ||
import { useNavigate } from "react-router-dom"; | ||
|
||
const MyInfo = () => { | ||
const [input, setInput] = useState({ | ||
password: "", | ||
hobby: "", | ||
}); | ||
const navigate = useNavigate(); | ||
const userToken = localStorage.getItem("userToken"); | ||
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. p3: tsx 파일에서 토큰을 가져오는 것과, axios 쏠때 토큰을 가져오는 것중 어디에서 받아오는게 좋을지 고민을 했었는데요. 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. p5: 토큰 처리는 axios instance 만들어서 사용하면 재사용성을 높일 수 있을것 같아요. const authClient = axios.create(authAxiosConfig);
authClient.interceptors.request.use(
async (config) => {
const accessToken = getAuthHeader();
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
} else {
console.error('토큰이 없습니다. 로그인이 필요합니다.');
window.location.replace('/auth/login');
}
return config;
},
(error) => {
console.error(error);
},
); |
||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
const { name, value } = e.target; | ||
setInput((prev) => ({ | ||
...prev, | ||
[name]: value, | ||
})); | ||
}; | ||
|
||
const handleSubmit = () => { | ||
if (userToken && (input.password || input.hobby)) { | ||
updateUserData({ | ||
hobby: input.hobby, | ||
password: input.password, | ||
userToken: userToken, | ||
}); | ||
alert("수정에 성공했습니다!"); | ||
navigate("/"); | ||
} else { | ||
alert("칸을 입력해주세요."); | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
<h1>내 정보 수정하기</h1> | ||
<h2>새 비밀번호</h2> | ||
<div className="search_sec"> | ||
<input | ||
name="password" | ||
value={input.password} | ||
css={mypageInput} | ||
type="password" | ||
onChange={handleInputChange} | ||
/> | ||
</div> | ||
|
||
<h2>새 취미</h2> | ||
<div className="search_sec"> | ||
<input | ||
onChange={handleInputChange} | ||
name="hobby" | ||
value={input.hobby} | ||
css={mypageInput} | ||
type="text" | ||
/> | ||
<Button type="button" onClick={handleSubmit}> | ||
수정하기 | ||
</Button> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default MyInfo; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** @jsxImportSource @emotion/react */ | ||
import { mypageInput } from "../pages/myPage/MyPage.style"; | ||
import Button from "./common/Button/Button"; | ||
import useGetMyHobby from "../libs/apis/useGetMyHobby"; | ||
import useGetUserHobby from "../libs/apis/useGetUserHobby"; | ||
import { hobbyPstyle } from "../pages/myPage/MyPage.style"; | ||
import { useState } from "react"; | ||
|
||
const SearchHobby = () => { | ||
const [userNo, setUserNo] = useState(0); | ||
const [hobby, setHobby] = useState(""); | ||
|
||
const userToken = localStorage.getItem("userToken"); | ||
|
||
const { myHobby } = useGetMyHobby(userToken); | ||
const { userHobby } = useGetUserHobby({ userToken, userNo }); | ||
|
||
const handleClickSearch = () => { | ||
if (userHobby) { | ||
setHobby(userHobby); | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
<h1>취미</h1> | ||
<h2>나의 취미</h2> | ||
<p css={hobbyPstyle}>{myHobby}</p> | ||
<h2>다른 사람들의 취미</h2> | ||
<div className="search_sec"> | ||
<input | ||
css={mypageInput} | ||
type="text" | ||
placeholder="사용자 번호" | ||
onChange={(e) => setUserNo(Number(e.target.value))} | ||
/> | ||
<Button type="button" onClick={handleClickSearch}> | ||
검색 | ||
</Button> | ||
</div> | ||
{hobby && ( | ||
<p css={hobbyPstyle}> | ||
{userNo}번 사용자의 취미: {hobby} | ||
</p> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default SearchHobby; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { css } from "@emotion/react"; | ||
import { Theme } from "../../../styles/theme"; | ||
|
||
export const buttonStyle = css` | ||
width: 100%; | ||
padding: 0.7rem 1rem; | ||
margin-bottom: 0.5rem; | ||
color: ${Theme.color.white}; | ||
background-color: ${Theme.color.lightGray_1}; | ||
border: 0px solid; | ||
border-radius: 5px; | ||
cursor: pointer; | ||
:hover { | ||
background-color: ${Theme.color.lightGray_3}; | ||
transition: all 1s; | ||
} | ||
&:disabled { | ||
background-color: #cccccc; | ||
cursor: not-allowed; | ||
opacity: 0.5; | ||
} | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** @jsxImportSource @emotion/react */ | ||
import { ButtonHTMLAttributes, ReactNode } from "react"; | ||
import { buttonStyle } from "./Button.style"; | ||
|
||
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { | ||
children: ReactNode; | ||
} | ||
Comment on lines
+5
to
+7
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. p3 : 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. p5: 왕 .. 전 진짜 이번 과제에서 버튼 분리할 생각도 못했는데 진짜 한서님 코드 보고 저 정말 깨달음을 얻었어요!!! |
||
|
||
const Button = ({ children, disabled, ...props }: ButtonProps) => { | ||
return ( | ||
<button {...props} css={buttonStyle} disabled={disabled}> | ||
{children} | ||
</button> | ||
); | ||
}; | ||
Comment on lines
+9
to
+15
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. p3 : 와우!! 이게 pr에 작성해주신 코드네요!! 저는 공통 컴포넌트 구현할 때 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.
|
||
|
||
export default Button; |
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.
p3: 옹
.env
가 올라와있는데 혹시 과제 채점때문에 함께 올려주신건가요?!gitignore
하시지 않은 이유가 궁금합시당