- React ์ฃผํน๊ธฐ ์ฃผ์ฐจ Lv.5 ๊ณผ์
- ์ ์ํ
- ๋ฐฐํฌํ ์ฌ์ดํธ: vercel
- ๋ ๋ฒจ 4 ๊ณผ์ ์ ์ด์ ๋ถ์ฌ, ๋๋ง์ React App ์ ๋ง๋ค์ด๋ด
์๋ค.
- ์ฃผ์ ๋ ๋ฐ๋์ Todo List๊ฐ ์๋์ฌ๋ ๋ฉ๋๋ค. ๋ณธ๋ฌธ๊ณผ ๋๊ธ์ ๊ฐ์ง ๊ตฌ์กฐ์ ์น ์๋น์ค๋ฉด OK!
- ์ํ๊ด๋ฆฌ ( ์ ์ง / ์ด๊ธฐํ ) ๊ฐ ์ ๋์ด์๋์?
- ๊ฐ ์ปดํฌ๋ํธ์ ์ฌ์ฌ์ฉ์ฑ์ด ๋๋์?
- ์์ธ์ฒ๋ฆฌ๊ฐ ๋ฏธํกํ ๋ถ๋ถ์ ์๋์?
- (1) ๊ณตํต
- UI ๊ตฌํํ๊ธฐ
- API ๋ช ์ธ์ ์์ฑํ๊ธฐ
- (2) ๋ณธ๋ฌธ (ex: ํ ์ผ) CRUD ๊ตฌํ
- ๋ณธ๋ฌธ ๋ฆฌ์คํธ ์กฐํ ํ๊ธฐ
- ๋ณธ๋ฌธ ์กฐํ ํ๊ธฐ
- ๋ณธ๋ฌธ ์ถ๊ฐ ํ๊ธฐ
- ๋ณธ๋ฌธ ์ญ์ ํ๊ธฐ
- ๋ณธ๋ฌธ ์์ ํ๊ธฐ
- (3) ๋ฐฐํฌ
- json-server ์๋ฒ ๋ฐฐํฌ
- ๋ฆฌ์กํธ ํ๋ก์ ํธ ๋ฐฐํฌ (S3, vercel ๋ฑ ์์ )
- (1) UI/UX
- ์ฐฝ์์ ์ธ UI/UX๋ก ๊ณผ์ ๋ฅผ ๋ง๋์ธ์.
- ์์์ ์์ด๋ ๋ง๋ค๊ณ ์ถ์ ๊ธฐ๋ฅ์ด ์๋ค๋ฉด OK!
- (2) ํ์ ์๊ตฌ ์ฌํญ
- ๋์ ๋ผ์ฐํ ์ ์ฌ์ฉํ์ธ์.
- 1๊ฐ ์ด์์
Custom Hook
์ ๊ตฌํํ์ธ์. - Form์ ์ ํจ์ฑ ๊ฒ์ฆ ๊ธฐ๋ฅ์ ์ ์ฉํ์ธ์. ์ ํจ์ฑ ๊ฒ์ฆ์ด๋, ์๋์ ์์๋ค์ ์๋ฏธํฉ๋๋ค.
- ex: ์ ๋ชฉ์ 10๊ธ์ ์ด์ ๊ธฐ์
ํ์ง ์์ผ๋ฉด, ๊ธ์ ์ถ๊ฐํ ์ ์๋๋ก ์ ํ โ
Alert
์ผ๋ก ์๋ด - ex: Form์์ ๋ชจ๋ input์ ๊ฐ์ ์ ๋ ฅํ์ง ์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ
- ex: ์ ๋ชฉ์ 10๊ธ์ ์ด์ ๊ธฐ์
ํ์ง ์์ผ๋ฉด, ๊ธ์ ์ถ๊ฐํ ์ ์๋๋ก ์ ํ โ
- ๋ฒํผ ์ปดํฌ๋ํธ 1๊ฐ๋ก ๋ชจ๋ ๋ฒํผ์ ๊ตฌํํ์ธ์. ๋ชจ๋ ์คํ์ผ๊ณผ ๊ธฐ๋ฅ์ ๋ฒํผ์ ๊ตฌํํ ์ ์๋ ๋ง๋ฅ ๋ฒํผ์ ๋ง๋ค์ด๋ณด๋ ๊ฒ ์ ๋๋ค.
development
ํ๊ฒฝ์์๋งredux devtool
์ด ํ์ฑํ ๋๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.- ๋ฐฐํฌ๋ ๊ฒฐ๊ณผ๋ฌผ์์๋
console.log()
๊ฐ ๋ณด์ด์ง ์๋๋ก ์ฒ๋ฆฌํฉ๋๋ค. .env
๋ฅผ ์ด์ฉํด์ API ์๋ฒ์ URL ์ฝ๋์์์ ์จ๊ธฐ๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- (3) API ๋ช ์ธ์ (ํ๋ก์ ํธ ์๋ฃ ํ ์์ฑ) ํ๋ก์ ํธ๊ฐ ์๋ฃ๋์๋ค๋ฉด, ๊ฐ์ด API ์๋ฒ์์ ์ด๋ค API๋ฅผ ์ฌ์ฉํ์๋์ง ๋ช ์ธ์๋ฅผ ์์ฑํด์ฃผ์ธ์.
๐ Challenge: ๋์ ํด๋ณผ๋งํ ํค์๋๋ฅผ ๋๋ฆฝ๋๋ค. ๊ฒ์์ ํตํด ๊ฐ ํค์๋๋ค์ด ์ด๋ค ๊ธฐ๋ฅ์ธ์ง ์ฐพ์๋ณด๊ณ ๋์ ํด๋ณด์ธ์. (ํ์ โ)
- Infinite Scroll ๋๋ Pagination
- ํ ์ผ ๋๋ ๋๊ธ์ด ์์ด ๋ง์ ๋, ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํ๋ฒ์ ๋ถ๋ฌ์ค๋ ๊ฒ์ด ์๋๋ผ ์คํฌ๋กค์ด ๊ฐ์ฅ ์๋์ ๋๋ฌํ ๋๋ง๋ค ๋ถ๋ถ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ Fetching ํ๋๋ก ๊ตฌํํด๋ด ๋๋ค.
- Form Help Text
- Form์ ์ ํจ์ฑ์ ์ฒดํฌํ๊ณ , ์ ํจ์ฑ์ ์ฒดํฌ ํ์ง ๋ชปํ์ ๋ ์ฌ์ฉ์์๊ฒ ์ ํจ์ฑ์ ์ฒดํฌ ํ์ง ๋ชปํ ์ด์ ์ ๋ํด์ ์๋ดํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํด๋ด ๋๋ค.
์ฌ์ฉ์ ์ธ์ฆ/์ธ๊ฐ (JWT ๊ด๋ฆฌ: LocalStorage => Cookie๋ก ๋ณ๊ฒฝ)
- ์๋ฒ ์ฌ์ด๋ ์ ์ญ ์ํ ๊ด๋ฆฌ:
- axios
- json-server
- TanStackQuery
- ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์ ์ญ ์ํ ๊ด๋ฆฌ ๋ฐ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ๊ด๋ฆฌ:
- axios
https://moneyfulpublicpolicy.co.kr
api- Local Storage
- Redux Tool Kit
- ์ฟ ํค์์ ๊ด๋ฆฌ:
- axios
https://moneyfulpublicpolicy.co.kr
api- cookie
- json-server => ๋ฌด๋ฃ ์ฌ์ฉ ๊ฐ๋ฅํด์ glitch๋ก json ๋ฐฐํฌ
- vercel ๋ฐฐํฌ
- ํฌ๋ CRUD
- ํฌ๋ ๋ณ ์์ธํ์ด์ง ๋๊ธ CRUD
api = ๋ฐฐํฌํ json ์๋ฒ
authApi = https://moneyfulpublicpolicy.co.kr
๊ตฌ๋ถ | ๊ธฐ๋ฅ | URL | Method | request | response |
---|---|---|---|---|---|
Auth | ํ์๊ฐ์ | authApi/register | POST | { "id": "์ ์ ์์ด๋", "password": "์ ์ ๋น๋ฐ๋ฒํธ", "nickname": "์ ์ ๋๋ค์" } |
status: 201 Created { "message": "ํ์๊ฐ์ ์๋ฃ", "success": true } status: 401 Unauthorized { "message": "์์ด๋, ๋น๋ฐ๋ฒํธ, ๋๋ค์์ ํ์๊ฐ์ ๋๋ค." } status: 409 Conflict { "message": "์ด๋ฏธ ์กด์ฌํ๋ ์ ์ id์ ๋๋ค." } |
Auth | ๋ก๊ทธ์ธ | authApi/login | POST | { "id": "์ ์ ์์ด๋", "password": "์ ์ ๋น๋ฐ๋ฒํธ" } |
status: 200 OK { "accessToken": "์ต์ธ์ค ํ ํฐ", "userId": "์ ์ ์์ด๋", "success": true, "avatar": null, "nickname": "๋๋ค์"(๊ธฐ๋ณธ๊ฐ "์ต๋ช "์ผ๋ก ์ค์ ) } status: 401 Unauthorized { "message": "id๋ 4๊ธ์ ์ด์์ ๋ฌธ์์ด์ด์ด์ผ ํฉ๋๋ค." } status: 401 Unauthorized { "message": "์กด์ฌํ์ง ์๋ ์ ์ ์ ๋๋ค." } status: 401 Unauthorized { "message": "password๋ 4๊ธ์ ์ด์์ ๋ฌธ์์ด์ด์ด์ผ ํฉ๋๋ค." } status: 401 Unauthorized { "message": "๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค." } |
Auth | ์ ์ ์กฐํ | authApi/user | GET | {Authorization: Bearer ์ต์ธ์คํ ํฐ} | status: 200 OK { "id": "์ ์ ์์ด๋", "nickname": "๋๋ค์" "avatar": null, "success": true,} status: 401 Unauthorized(ํ ํฐ ์๋ ๊ฒฝ์ฐ) { "message": "ํค๋์ authorization ์ ๋ณด๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค." } |
Todo | ์ ์ฒด ํฌ๋ ์กฐํ | /api/todoList | GET | - | { "todoList": [ { "id": "ํฌ๋ ์์ด๋", "userId": "์ ์ ์์ด๋", "title": "์ ๋ชฉ", "content": "๋ด์ฉ", "isDone": ๋ถ๋ฆฌ์ธ ๊ฐ }, { "id": "ํฌ๋ ์์ด๋", "userId": "์ ์ ์์ด๋", "title": "์ ๋ชฉ", "content": "๋ด์ฉ", "isDone": ๋ถ๋ฆฌ์ธ ๊ฐ }, ... ] |
Todo | ํฌ๋ ์์ธ ์กฐํ | /api/todoList/:id | GET | {id: id} | { "id": "ํฌ๋ ์์ด๋", "userId": "์ ์ ์์ด๋", "title": "์ ๋ชฉ", "content": "๋ด์ฉ", "isDone": ๋ถ๋ฆฌ์ธ ๊ฐ } |
Todo | ํฌ๋ ์์ฑ | /api/todoList/:id | POST | { "id": "ํฌ๋ ์์ด๋"(์๋ ์์ฑ), "userId": "์ ์ ์์ด๋", "title": "์ ๋ชฉ", "content": "๋ด์ฉ", "isDone": false (์ด๊ธฐ๊ฐ false) } |
|
Todo | ํฌ๋ ์ญ์ | /api/todoList/:id | DELETE | {id: id} | |
Todo | ํฌ๋ ์์ | /api/todoList/:id | PATCH | { ...currentTodo, "title": "์์ ํ ์ ๋ชฉ", "content": "์์ ํ ๋ด์ฉ", } |
|
Todo | ํฌ๋ ์์ (isDone ํ ๊ธ) | /api/todoList/:id | PATCH | { ...currentTodo, "isDone": !currentTodo.isDone } |
|
Comment | ํฌ๋ ๋ณ ๋๊ธ ๋ฆฌ์คํธ ์กฐํ | /api/comments?todoId=:id | GET | {id: id} | [ { "id": "๋๊ธ ์์ด๋", "userId": "์ ์ ์์ด๋", "todoId": "๋์ผํ ํฌ๋ ์์ด๋", "comment": "๋๊ธ" }, { "id": "๋๊ธ ์์ด๋", "userId": "์ ์ ์์ด๋", "todoId": "๋์ผํ ํฌ๋ ์์ด๋", "comment": "๋๊ธ" }, ] |
Comment | ๋๊ธ ์์ฑ | /api/comments | POST | { "id": "๋๊ธ ์์ด๋"(์๋ ์์ฑ), "userId": "์ ์ ์์ด๋", "todoId": "ํฌ๋ ์์ด๋", "comment": "๋๊ธ" } |
|
Comment | ๋๊ธ ์ญ์ | /api/comments/:id | DELETE | {id: id} | |
Comment | ๋๊ธ ์์ | /api/comments/:id | PATCH | { ...currentComment, "comment": "์์ ํ ๋๊ธ" } |
1. Custom Hook์ ๊ตฌํํ์ค ๋ ์ด๋ค ๊ธฐ๋ฅ์ ์ํด ์ฌ์ฉํ์ จ๋์? ๋ํ Custom Hook์ ์ฌ์ฉํจ์ผ๋ก์จ ์ด๋ค ์ด์ ์ ์ป์ผ์ จ๋์?
- ๋ฆฌ์กํธ ํฌํ ์ฌ์ฉ์ ์ํ modal ํ ์์ฑ
- ์ด์ : ํ์ํ ๊ณณ์์ ๋น ๋ฅด๊ณ ๊ฐํธํ๊ฒ ํธ์ถ ๊ฐ๋ฅ
- ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ก์ง ๋ถ๋ฆฌ๋ฅผ ์ํด mutate, query ํ ์์ฑ
- ์ด์ : ์ปดํฌ๋ํธ ๋ด๋ถ ๋ก์ง ๋ณต์ก์ฑ ๊ฐ์ ๋ฐ ๊ฐ๋ ์ฑ ํฅ์
- ๋จ์ : ํ์ผ์ ์ฆ๊ฐ
- ๋ณด์
- ์๋ฒ ์ํ ๊ด๋ฆฌ: ์๋ฒ์์ ๋ฐ์์ค๋ TodoList, Comments์ ๊ฒฝ์ฐ TanStackQuery์ผ๋ก ๊ด๋ฆฌ
- ํด๋ผ์ด์ธํธ ์ํ ๊ด๋ฆฌ: Error, Modal ๋ฑ์ useState ๋ฐ ๋ฆฌ๋์ค ํดํท์ผ๋ก ๊ด๋ฆฌ