Skip to content

๐Ÿ ์›ํ‹ฐ๋“œ ํ”„๋ฆฌ์˜จ๋ณด๋”ฉ ์ธํ„ด์‹ญ 1์ฃผ์ฐจ ๊ณผ์ œ - To Do List

License

Notifications You must be signed in to change notification settings

wanted-FE-team1/pre-onboarding-11th-1-1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

85 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

preonboarding

์›ํ‹ฐ๋“œ ํ”„๋ฆฌ์˜จ๋ณด๋”ฉ ํ”„๋ก ํŠธ์—”๋“œ ์ธํ„ด์‹ญ 1์ฃผ์ฐจ ๊ณผ์ œ

๋™๋ฃŒํ•™์Šต์„ ํ†ตํ•ด์„œ ํŒ€์—์„œ ์ƒ๊ฐํ•œ ์›ํ‹ฐ๋“œ ํ”„๋ฆฌ์˜จ๋ณด๋”ฉ ํ”„๋ก ํŠธ์—”๋“œ ์ธํ„ด์‹ญ ์„ ๋ฐœ ๊ณผ์ œ์˜ Best Pratice๋ฅผ ๋งŒ๋“ค๊ณ  ์ œ์ถœํ•ด์ฃผ์„ธ์š”.
Best Practice๋ž€ ๋ชจ๋ฒ”์‚ฌ๋ก€๋ผ๋Š” ๋ง๋กœ์„œ, ํŠน์ • ๋ฌธ์ œ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€์žฅ ์„ฑ๊ณต์ ์ธ ํ•ด๊ฒฐ์ฑ… ๋˜๋Š” ๋ฐฉ๋ฒ•๋ก ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ง„ํ–‰ ๊ธฐ๊ฐ„: 2023.06.27 ~ 2023.06.30






๋ชฉ์ฐจ


๐Ÿ”— ๋ฐฐํฌ ๋งํฌ

https://todolist-1-1.vercel.app/


โš™๏ธ ์‹คํ–‰ ๋ฐฉ๋ฒ•

$ npm install
$ npm start

๐Ÿ”— ์‚ฌ์ „ ์„ ๋ฐœ ๊ณผ์ œ

์ด๋ฆ„ GitHub Repository
๊ถŒ๋ฒ”์ค€ @kjungit
๊น€ํ˜„์ง„ @who0803
๋ฐ•ํฌ์ง„ @hihijin
์†์ˆ˜๋ฏผ @sonmansu
์œ ์ง€ํ˜„ @yoojiih
์ „์˜๋ฒ” @Boom0704
ํƒœ๊ฐ•ํฌ @khkh0109

๐Ÿค ํŒ€ ๊ทœ์น™

๋ธŒ๋žœ์น˜ ์ „๋žต

  • upstream์—๋Š” main ๋ธŒ๋žœ์น˜๋งŒ ์กด์žฌ
  • ๋ธŒ๋žœ์น˜๋ช…: feature/#์ด์Šˆ๋ฒˆํ˜ธ-๊ฐ„๋‹จํ•œ์„ค๋ช…
    • ex: feature/#7-setting
  • fork ํ•ด์„œ ๋ธŒ๋žœ์น˜ํŒŒ์„œ ์ž‘์—…ํ•œ๋’ค origin:main์œผ๋กœ PR ๋‚ ๋ฆผ
  • ์ฝ”๋“œ๋ฆฌ๋ทฐ ๋ฐ›๊ณ  ์Šน์ธ ๋ฐ›์œผ๋ฉด origin:main์— merge

์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ปจ๋ฒค์…˜

ํƒ€์ž… ์„ค๋ช…
Feat ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€
Fix ๋ฒ„๊ทธ ์ˆ˜์ •
Env ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๊ด€๋ จ
Style ์ฝ”๋“œ ์Šคํƒ€์ผ ์ˆ˜์ • (์„ธ๋ฏธ ์ฝœ๋ก , ์ธ๋ดํŠธ ๋“ฑ์˜ ์Šคํƒ€์ผ์ ์ธ ๋ถ€๋ถ„๋งŒ)
Refactor ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง (๋” ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋กœ ๋ณ€๊ฒฝ ๋“ฑ)
Design CSS ๋“ฑ ๋””์ž์ธ ์ถ”๊ฐ€/์ˆ˜์ •iE
Comment ์ฃผ์„ ์ถ”๊ฐ€/์ˆ˜์ •
Docs ๋‚ด๋ถ€ ๋ฌธ์„œ ์ถ”๊ฐ€/์ˆ˜์ •
Test ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€/์ˆ˜์ •
Chore ๋นŒ๋“œ, ํŒจํ‚ค์ง€ ๊ด€๋ จ ์ฝ”๋“œ ์ˆ˜์ •
Rename ํŒŒ์ผ ๋ฐ ํด๋”๋ช… ์ˆ˜์ •
Remove ํŒŒ์ผ ์‚ญ์ œ

๐Ÿ“‚ ํด๋” ๊ตฌ์กฐ

๐Ÿ“ฆsrc
  โ”œโ”€โ”€ ๐Ÿ“„index.css
  โ”œโ”€โ”€ ๐Ÿ“„index.tsx
  โ”œโ”€โ”€ ๐Ÿ“„App.tsx
  โ”œโ”€โ”€ ๐Ÿ“‚components
  โ”œโ”€โ”€ ๐Ÿ“‚hooks
  โ”œโ”€โ”€ ๐Ÿ“‚pages
  โ”œโ”€โ”€ ๐Ÿ“‚routers
  โ”œโ”€โ”€ ๐Ÿ“‚types
  โ””โ”€โ”€ ๐Ÿ“‚utils

๐Ÿ› ๏ธ ๊ธฐ์ˆ  ์Šคํƒ


๐Ÿ“– ์„œ๋น„์Šค ์†Œ๊ฐœ

๊ธฐ๋Šฅ ๊ตฌํ˜„

  • ํšŒ์› ๊ฐ€์ž…
  • ๋กœ๊ทธ์ธ
  • Todo CRUD
  • ํ† ํฐ ์œ ๋ฌด์— ๋”ฐ๋ฅธ ํŽ˜์ด์ง€ ๋ฆฌ๋‹ค์ด๋ ‰์…˜

ํŽ˜์ด์ง€

ํšŒ์›๊ฐ€์ž…
แ„’แ…ฌแ„‹แ…ฏแ†ซแ„€แ…กแ„‹แ…ตแ†ธ
๋กœ๊ทธ์ธ
แ„…แ…ฉแ„€แ…ณแ„‹แ…ตแ†ซ
Todo
todo

๐Ÿ‘‘ Best Practice

์„ ์ • ๊ธฐ์ค€

  1. ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ ๋ฐ ์žฌ์‚ฌ์šฉ์„ฑ
  • ๊ฐ€๋…์„ฑ์€ ํ˜‘์—…์„ ํ•˜๋ฉด์„œ๋„ ์ค‘์š”ํ•˜๋ฉฐ, ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ
  • ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ตœ์†Œํ™” ํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ์ž‘์„ฑ(useHook)
  1. ํ™•์žฅ์„ฑ
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ธฐ๋Šฅ์„ ์œ ์—ฐํ•˜๊ฒŒ ํ™•์žฅํ•˜๊ณ  ์œ ์ง€ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑ
  1. ์‚ฌ์šฉ์ž ํŽธ์˜์„ฑ
  • ์‚ฌ์šฉ์ž๋“ค์ด ์›น ๋˜๋Š” ์•ฑ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„

์ˆ˜ํ–‰ ๋ฐฉํ–ฅ

  • Best Practice๋ฅผ ์„ ์ •ํ•˜๊ธฐ์ „ ๊ฐ์ž ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋ฅผ ์„ค๋ช…ํ•˜๋ฉฐ ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ ์ง„ํ–‰
  • ๊ฐ์ž ๋งก์€ ์ฝ”๋“œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•๋“ค์„ ์ •๋ฆฌ ํ›„ ์Šคํฌ๋Ÿผ์„ ํ†ตํ•ด Best Practice ์„ ์ •
  • ์ฝ”๋“œ์ปจ๋ฒค์…˜ ๋ฐ ์–ธ์–ด, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํด๋”๊ตฌ์กฐ ์ •๋ฆฌ
  • Best Practice๋กœ ๋ฝ‘ํžŒ ๊ตฌํ˜„๋ฐฉ์‹์ค‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ๋ถ€๋ถ„๋“ค์„ ๋‚˜๋ˆ„์–ด ์—…๋ฌด ๋ถ„๋‹ด
  • ์ด์Šˆ ์ž‘์„ฑ ๋ฐ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ฝ”๋“œ ๊ตฌํ˜„ ํ›„ pr ํ›„ ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ ์ง„ํ–‰ ํ•˜๊ณ  merge

๊ตฌํ˜„์‚ฌํ•ญ


๐Ÿ“Œ Todo ์ปดํฌ๋„ŒํŠธ

  1. Todo ๊ด€๋ จ ๋กœ์ง์„ ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋ถ„๋ฆฌ
  • ๊ธฐ์กด TodoPage์™€ TodoList์— ํ˜ผ์žฌ๋ผ์žˆ๋˜ Todo ๊ด€๋ จ ๋กœ์ง์„ useTodo ๋ผ๋Š” ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋ถ„๋ฆฌ์‹œํ‚ด. ์ด๋Ÿฌํ•œ ๋ถ„๋ฆฌ๋Š” ๋‹ค์Œ์˜ ์ด์ ์„ ๊ฐ€์ง„๋‹ค๊ณ  ํŒ๋‹จํ•จ
    • Todo ๊ด€๋ จ ๋กœ์ง์€ useTodo ํ›…์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋ฉฐ, ์ด๋กœ ์ธํ•ด ์‘์ง‘๋ ฅ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋จ
    • ์ถ”ํ›„์— Todo๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ด ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด useTodo ํ›… ๋‚ด์—์„œ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋จ
    • TodoPage ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ, TodoPage ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ๊ด€์‹ฌ์‚ฌ๊ฐ€ ๋ถ„๋ฆฌ๋จ
  1. Todo ์•„์ดํ…œ์˜ ์ˆ˜์ • ์ƒํƒœ๋ฅผ state ๋ณ€์ˆ˜๋กœ ๊ด€๋ฆฌ
  • ํˆฌ๋‘ ์•„์ดํ…œ์˜ ์ˆ˜์ • ์ƒํƒœ๋ฅผ TodoItem ๋‚ด์˜ ์ƒํƒœ ๋ณ€์ˆ˜๋กœ ๊ด€๋ฆฌํ• ์ง€, Todo ๊ฐ์ฒด์˜ ์†์„ฑ์œผ๋กœ ๊ด€๋ฆฌํ• ์ง€์— ๋Œ€ํ•œ ๋…ผ์˜ ํ›„์— ์ƒํƒœ ๋ณ€์ˆ˜๋กœ ๊ฒฐ์ •

    1. TodoItem ์ปดํฌ๋„ŒํŠธ ๋‚ด์˜ ์ƒํƒœ ๋ณ€์ˆ˜๋กœ ์ˆ˜์ • ์ƒํƒœ ๊ด€๋ฆฌ
    export default function TodoItem({id, todo, isCompleted, updateTodo, deleteTodo
    }: TodoItemProps) {
      const [isOnModify, setIsOnModify] = useState(false);
    1. TOdo ๊ฐ์ฒด์˜ ์†์„ฑ์œผ๋กœ ์ˆ˜์ • ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌ
    export interface Todo {
      id: number;
      isCompleted: boolean;
      todo: string;
      isOnModify: boolean; // ์ถ”๊ฐ€
    }

    ํ›„์ž์˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ Todo๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ๋งˆ๋‹ค ์„ ํƒ๋œ Todo์— ํ•ด๋‹นํ•˜๋Š” Todo๋ฅผ Todo ๋ฐฐ์—ด์—์„œ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•˜๋Š” ๋น„ํšจ์œจ์ด ์กด์žฌํ•จ. ๋˜ํ•œ, Todo ๋ฐฐ์—ด์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ถ€๋ชจ (TodoPage) ์ปดํฌ๋„ŒํŠธ๋ถ€ํ„ฐ ๋ฆฌ๋žœ๋”๋ง์ด ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์กด์žฌํ•จ

    ๋ฐ˜๋ฉด, ์ „์ž์˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋ถˆํ•„์š”ํ•œ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฆฌ์ง€ ์•Š์•„๋„ ๋˜๊ณ  ์ž์‹ (TodoItem) ์ปดํฌ๋„ŒํŠธ๋งŒ ๋ฆฌ๋žœ๋”๋ง๋จ

  1. Todo ์ˆ˜์ • ์‹œ setTodo ํ˜ธ์ถœ๋กœ ๋ฆฌ๋žœ๋”๋งํ•˜๊ธฐ
  • Todo๋ฅผ ์ˆ˜์ •ํ•œ ํ›„, ๋ณ€๊ฒฝ๋œ Todo๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•จ

    1. getTodos API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ „์ฒด Todo ๋ฐฐ์—ด์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•
    2. setTodos๋งŒ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•

    Todo ์ˆ˜์ •ํ•  ๋•Œ getTodos API๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ์ €์žฅ ์‹œ ๊นœ๋นก์ž„ ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚จ update api ํ˜ธ์ถœ์ด ์„ฑ๊ณตํ–ˆ๋‹ค๋ฉด, todo๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋‹จ ๊ฒƒ์ด ๋•Œ๋ฌธ์— getTodos api๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ํŒ๋‹จ๋˜์–ด setTodos๋งŒ ํ˜ธ์ถœํ•˜๊ธฐ๋กœ ํ•จ ์ด ๋ฐฉ์‹์€ ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ๊ณผ ๊นœ๋นก์ž„ ๋ฌธ์ œ๋ฅผ ์—†์•จ ์ˆ˜ ์žˆ์Œ


๐Ÿ“Œ ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ•œ validation ์œ ํ‹ธ ํ•จ์ˆ˜

  • input values๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ error message์™€ isDiabled ์š”์†Œ๋ฅผ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” ์œ ํ‹ธ ํ•จ์ˆ˜
  • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋กœ์ง์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์œ ํ‹ธ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋กœ์ง์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ™•์žฅ์„ฑ ์žˆ๊ฒŒ ๊ตฌํ˜„
const validateInput = ({ authInput, validate }) => {
  const error = validate(authInput);

  const isValid = () => {
    return (
      Object.values(error).every((err) => err === '') &&
      Object.values(authInput).every((val) => val !== '')
    );
  };

  return {
    error,
    isDisabled: !isValid(),
  };
};

๐Ÿ“Œย localStorage ํ•จ์ˆ˜ํ™”

  • localStorage key๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ ํ•จ์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ํšจ๊ณผ์ ์ผ ๊ฒƒ์ด๋ผ๊ณ  ํŒ๋‹จ
  • get, remove์‹œ key๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š์•„๋„ ํ•จ์ˆ˜๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ”๋กœ ํ† ํฐ์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ๋ณ€๊ฒฝ
export const getAccessToken = (): string | null => {
  const accessToken = localStorage.getItem('accessToken');
  return accessToken;
};

export const setAccessToken = (accessToken: string) => {
  localStorage.setItem('accessToken', accessToken);
};

export const removeAccessToken = () => {
  localStorage.removeItem('accessToken');
};

๐Ÿ“Œ axios ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ

  • ๋…ผ์˜: ํ† ํฐ์ด ํ•„์š”ํ•œ ์š”์ฒญ๊ณผ ํ•„์š”์—†๋Š” ์š”์ฒญ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ถ„๋ฆฌ vs ํ•œ๊ฐ€์ง€ ์ธ์Šคํ„ด์Šค๋งŒ ๋‘๊ณ  ํ† ํฐ ์œ ๋ฌด์—๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ
  • ๋ฌธ์ œ์ : axios ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ตณ์ด 2๊ฐœ๋ผ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์กŒ๊ณ , ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์“ธ ๋•Œ ํ† ํฐ์ด ํ•„์š”ํ•œ ์š”์ฒญ์ธ์ง€ ์•„๋‹Œ ์š”์ฒญ์ธ์ง€ ๊ฐ์ž ๊ตฌ๋ถ„ํ•ด์„œ ์จ์•ผํ•ด์„œ ๋ฒˆ๊ฑฐ๋กœ์›€
//ํ† ํฐ์ด ํ•„์š”ํ•œ ์š”์ฒญ๊ณผ ํ•„์š”์—†๋Š” ์š”์ฒญ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ถ„๋ฆฌ
//๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ† ํฐ์ด ํ•„์š”ํ•œ ์š”์ฒญ์ด๋ฉด tokenRequest ์‚ฌ์šฉ
//ํ† ํฐ์ด ํ•„์š”์—†๋Š” ์š”์ฒญ์ด๋ฉด nonTokenRequest ์‚ฌ์šฉ
const BASE_URL = process.env.REACT_APP_BASE_URL;
const nonTokenRequest = axios.create({ baseURL: BASE_URL });
const tokenRequest = axios.create({ baseURL: BASE_URL }
{
        headers: {
          "Content-Type": "application/json",
        },
      }
);
)

tokenRequest.interceptors.request.use(config => {
  config.headers = {
    Authorization: `Bearer ${localStorage.getItem("access_token")}`,
  };

  return config;
});
  • ํ•ด๊ฒฐ๋ฒ•:
    • axios ์ธ์Šคํ„ด์Šค๋ฅผ ์• ์ดˆ์— ํ•˜๋‚˜๋งŒ ๋‘๊ณ  localstorage์— ํ† ํฐ์ด ์žˆ๋‹ค๋ฉด ์ด์ œ๋Š” ํ† ํฐ์ด ํ•„์š”ํ•œ ์š”์ฒญ๋ฐ–์— ์—†์œผ๋ฏ€๋กœ localstorage์— ํ† ํฐ ์œ ๋ฌด๋งŒ ํ™•์ธ
    • ๋˜ํ•œ localstorage์— ํ† ํฐ์„ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ๋งŒ์•ฝ ํ† ํฐ์ด ์—†๋‹ค๋ฉด null๋กœ ๋ฐ›์•„์ง€๋ฏ€๋กœ ํ—ค๋”์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋‹ด๊ธฐ์ง€ ์•Š๊ฒŒ ๊ตฌํ˜„
//ํ•œ๊ฐ€์ง€ ์ธ์Šคํ„ด์Šค๋งŒ ๋‘๊ณ  ํ† ํฐ ์œ ๋ฌด์—๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ
export const API = axios.create({
  baseURL: 'https://www.pre-onboarding-selection-task.shop',
  headers: {
    'Content-Type': 'application/json',
  },
});

API.interceptors.request.use(
  (config) => {
    const accessToken = getAccessToken();

    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

๐Ÿ“Œ api์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ์„ ํƒ

  • ๋…ผ์˜: ํด๋ž˜์Šค ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•œ ์ •์  ๋ฉ”์„œ๋“œvs ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ
  • ๋ฌธ์ œ์  : ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์š”์ฒญ URL, ์ฝ”๋“œ์˜ ์ค‘๋ณต, ์ฝ”๋“œ์˜ ๊ตฌ์กฐํ™”๋ถ€์žฌ๋กœ ๊ฐ€๋…์„ฑ ์ €ํ•ด
export const TodoAPI = {
async get(): Promise<ITodoResponse[]> {
    const { data } = await API.get('/todos');
    return data;
  }

  async post(todo: string): Promise<ITodoResponse> {
    const { data } = await API.post('/todos', todo);
    return data;
  }

  async put(todo: ITodo, id: number): Promise<ITodoResponse> {
    const { data } = await API.put(`/todos/${id}`, todo);
    return data;
  }

  async delete(id: number): Promise<string> {
    const { data } = await API.delete(`/todos/${id}`);
    return data;
  }
}
  • ํ•ด๊ฒฐ๋ฒ•:
    • ํด๋ž˜์Šค ๊ตฌ์กฐ์™€ ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ์ ‘๊ทผ์œผ๋กœ ์ฝ”๋“œ์˜ ๊ตฌ์กฐํ™”์™€ ๋ชจ๋“ˆํ™”์‹œ์ผœ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ
    • private ๋ฉค๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด ์€๋‹‰๊ณผ ์บก์Šํ™”, ๊ณตํ†ต ์š”์ฒญ URL์„ ๊ด€๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์ค‘๋ณต ์ œ๊ฑฐํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ
export class TodoAPI {
  private static TODOS = '/todos';

  static async get(): Promise<ITodoResponse[]> {
    const { data } = await API.get(this.TODOS);
    return data;
  }

  static async post(todo: string): Promise<ITodoResponse> {
    const { data } = await API.post(this.TODOS, todo);
    return data;
  }

  static async put(todo: ITodo, id: number): Promise<ITodoResponse> {
    const { data } = await API.put(`${this.TODOS}/${id}`, todo);
    return data;
  }

  static async delete(id: number): Promise<string> {
    const { data } = await API.delete(`${this.TODOS}/${id}`);
    return data;
  }
}

๐Ÿ“Œ createBrowserRouter

  • ๊ธฐ์กด์˜ ๋ผ์šฐํŒ… ๊ธฐ๋Šฅ๋ณด๋‹ค ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์ด ์ถ”๊ฐ€๋˜์–ด ์žˆ์–ด ํ™œ์šฉ์„ฑ์ด ๋†’์Œ
  • loader, action ๋“ฑ์„ ํ†ตํ•ด์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๊ฐ€๋Šฅ
  • ๊ฒฝ๋กœ๊ฐ€ ๋งŽ๋‹ค๋ฉด ๊ฐ€๋…์„ฑ์ด ์ข‹์Œ

1. App.tsx ์—์„œ RouterProvider ์—ฐ๊ฒฐ

export const router = createBrowserRouter([
  {
    path: '/',
    element: <Root />,
    children: [
      {
        index: true,
        element: <Navigate to='/todo' />,
      },
      {
        path: 'signup',
        element: <JoinPage />,
        loader: redirectTodo,
      },
      {
        path: 'signin',
        element: <LoginPage />,
        loader: redirectTodo,
      },
      {
        path: 'todo',
        element: <TodoPage />,
        loader: redirectLogin,
      },
    ],
    errorElement: <NotFoundPage />,
  },
]);

๋ผ์šฐํŒ… ๊ตฌํ˜„ ์„ค๋ช…

  • ๋ผ์šฐํŒ…ํ•  path, element๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๋ผ์šฐํŒ… ์„ค์ •
  • children์—์„œ๋Š” ๋ฐฐ์—ด์— ์ค‘์ฒจ๋œ ๋ผ์šฐํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ
  • ํ˜„์žฌ todo ์—์„œ๋Š” โ€œ/โ€œ ๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ์— index๊ฐ’์„ true๋กœ ์„ค์ •ํ•˜์—ฌ โ€œ/โ€ ์ ‘๊ทผ์‹œ โ€œ/todoโ€ํŽ˜์ด์ง€๋กœ ์ „ํ™˜๋˜๋„๋ก ์„ค์ •

2. Outlet

export function Root() {
  return (
    <>
      <Header />
      <Outlet />
      <Footer />
    </>
  );
}

Outlet ๊ตฌํ˜„ ์„ค๋ช…

  • root๊ฒฝ๋กœ์—์„œ Header, Footer ์„ค์ •

3. redirect

export const redirectPage = () => {
  const token = getAccessToken();

  if (token === null) {
    return redirect('/signin');
  } else {
    return redirect('/todo');
  }
};

export const redirectLogin = () => {
  const token = getAccessToken();

  if (token === null) {
    return redirect('/signin');
  }

  return null;
};

export const redirectTodo = () => {
  const token = getAccessToken();

  if (token) {
    return redirect('/todo');
  }

  return null;
};

redirect ๊ตฌํ˜„ ์„ค๋ช…

  • createBrowserRouter์—์„œ loader๋กœ ํŽ˜์ด์ง€ ์ ‘๊ทผ์‹œ tokenํ™•์ธ ํ›„ redirect ์ฒ˜๋ฆฌ๋˜๋„๋ก ์„ค์ •

About

๐Ÿ ์›ํ‹ฐ๋“œ ํ”„๋ฆฌ์˜จ๋ณด๋”ฉ ์ธํ„ด์‹ญ 1์ฃผ์ฐจ ๊ณผ์ œ - To Do List

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published