๐Ÿ“† TODO APP ๋งŒ๋“ค๊ธฐ

์œ ์žํƒฑ์ž๐Ÿ‹ยท2021๋…„ 4์›” 27์ผ
0
post-thumbnail

๊ฐ„๋‹จํ•œ ์ผ์ •๊ด€๋ฆฌ ์•ฑ์„ ๋งŒ๋“ค์–ด ๋ณด์•˜๋‹ค.

๊ธฐ์กด์— ์•ฑ์˜ ๊ตฌ์กฐ์™€ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์„ค๊ณ„ํ•ด์•ผ ์ข‹์„์ง€ ๊ณ ๋ฏผ์ด ๋งŽ์•˜๋Š”๋ฐ, ํŠœํ† ๋ฆฌ์–ผ์„ ๋”ฐ๋ผ ์ง„ํ–‰ํ•˜๋‹ˆ ๊ฐœ๋…์ด ๋ณด๋‹ค ๋ช…ํ™•ํ•ด์ง„ ๊ฒƒ ๊ฐ™์•˜๋‹ค.(๋ฌผ๋ก  ์ •๋‹ต์€ ์—†์ง€๋งŒ)

๊ธฐ์กด ํ”„๋กœ์ ํŠธ์™€ ๋‹ฌ๋ฆฌ ์ปดํฌ๋„ŒํŠธ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋„ ๊ณ ๋ฏผํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ์˜€๋‹ค!๐Ÿค“


โš™๏ธ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ


๐Ÿ“Œ App.js / TodoTemplate.js

์ „์ฒด์ ์œผ๋กœ TodoTemplate์ปดํฌ๋„ŒํŠธ๊ฐ€ input ์ฐฝ๊ณผ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ๊ตฌ์กฐ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  TodoTemplate.js์—์„œ๋Š” ์ด๋ฅผ {children}์œผ๋กœ ๋ฐ›์•„์˜ค๊ณ  ์žˆ๋‹ค.

๐Ÿ” useRef ์‚ฌ์šฉํ•œ ์ด์œ 

id์€ ์ƒˆ๋กœ์šด ํ•ญ๋ชฉ์„ ๋งŒ๋“ค๋•Œ ์ฐธ์กฐ๋˜๋Š” ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— id๊ฐ€ ๋ฐ”๋€๋‹ค๊ณ  ํ•ด์„œ ๋‹ค์‹œ ๋žœ๋”๋ง๋  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋”ฐ๋ผ์„œ useRef๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ด€๋ฆฌํ•œ๋‹ค.

๐Ÿ” useCallback ์‚ฌ์šฉํ•œ ์ด์œ 

๐Ÿ‘‰ ๋žœ๋”๋ง ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด!
์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋žœ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํ•œ๋ฒˆ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ๋‹ค์‹œ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ” useCallback ์‚ฌ์šฉ๋ฒ•

์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ์ƒ์„ฑํ•˜๊ณ  ์‹ถ์€ ํ•จ์ˆ˜๋ฅผ, ๋‘ ๋ฒˆ์งธ ํŒŒ๋ฆฌ๋ฏธํ„ฐ์—๋Š” ์–ด๋–ค ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ๋ช…์‹œํ•ด์ค€๋‹ค(์˜์กด์„ฑ ๋ฐฐ์—ด).
onInsert ํ•จ์ˆ˜์—์„œ๋Š” setTodos๋ฅผ ํ†ตํ•ด todos ๊ฐ’์ด ๋ณ€ํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด์— todos๋ฅผ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.


๐Ÿ“Œ TodoInsert.js

1. onInsert ํ•จ์ˆ˜

input ์ฐธ์— ์ž…๋ ฅ๋œ ํ…์ŠคํŠธ๋ฅผ ๋ฐ›์œผ๋ฉด, ๋ณ€์ˆ˜ todo์— nextId์™€ text, checked๋ฅผ ํ• ๋‹นํ•ด์ค€๋‹ค. ๊ทธ ํ›„ concat ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•ด ๋ฐฐ์—ด์— ์ƒˆ๋กœ ์ž…๋ ฅ๋œ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ , nextId๋ฅผ ํ˜„์žฌ์˜ ๊ฐ’์—์„œ +1 ํ•ด์ค€๋‹ค.

๐Ÿ” form ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ 

input๊ณผ button ํƒœ๊ทธ๋ฅผ form ํƒœ๊ทธ๋กœ ๋ฌถ์–ด์ฃผ๊ณ , form ํƒœ๊ทธ ๋‚ด์—์„œ onSubmit ์ด๋ฒคํŠธ๋ฅผ ์ค€ ์ด์œ ๋Š” ๋ฒ„ํŠผ ํด๋ฆญ๊ณผ ์—”ํ„ฐ ํ‚ค๋กœ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
โž• ๋”๋ถˆ์–ด, semantic value์™€ ๊ฐ€๋…์„ฑ ์ธก๋ฉด์—์„œ๋„ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

onChange ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด input์— ์ž…๋ ฅ๋œ value ๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ์ถ”๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ onSubmit ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ, ์—ฌ๊ธฐ์—์„œ๋Š” value๋ฅผ onInsert์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„ฃ์–ด์ฃผ๊ณ  setvalue('')๋ฅผ ํ†ตํ•ด input ์ฐฝ์„ ์ดˆ๊ธฐํ™” ์‹œ์ผœ๋‘”๋‹ค.

e.preventDefault()๋Š” onSubmit ์ด๋ฒคํŠธ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ƒˆ๋กœ๊ณ ์นจ ์‹œํ‚ค๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ด์ค€๋‹ค.


๐Ÿ“Œ TodoList.js

App.js์—์„œ ๋„˜๊ฒจ์ค€ todos, onRemove, onToggle๋ฅผ props๋กœ ๋ฐ›๊ณ , map ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด TodoListItem ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.


๐Ÿ“Œ TodoListItem.js

App.js์—์„œ ๋„˜๊ฒจ์ค€ onRemove, onToggle ํ•จ์ˆ˜๋ฅผ props๋กœ ๋ฐ›๊ณ  ์žˆ๋‹ค.

1. onRemove ํ•จ์ˆ˜

ํด๋ฆญ๋œ ํ•ญ๋ชฉ์˜ id๋ฅผ ๋ฐ›์•„ ๋‹ค์‹œ setTodos๋ฅผ ํ•ด์ค€๋‹ค. ์—ฌ๊ธฐ์„œ ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ˜•ํ•˜์ง€ ์•Š๋Š” filter ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ฆญ๋œ ํ•ญ๋ชฉ ์ด์™ธ์˜ ๊ฒƒ๋งŒ ๋‚จ๊ฒจ์ค€๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ state todos๊ฐ€ ๋ณ€ํ˜•๋˜์—ˆ์„ ๋•Œ ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ์˜์กด์„ฑ ๋ฐฐ์—ด์— todos๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ , useCallback ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ์ฃผ์–ด ๋žœ๋”๋ง ์„ฑ๋Šฅ์„ ์ตœ์ ํ™” ํ•ด์ค€๋‹ค.

2. onToggle ํ•จ์ˆ˜

์ฒดํฌํ•˜๋ฉด ๊ฐ€์šด๋ฐ ์„ ์ด ์ƒ๊ธฐ๊ณ  ๋‹ค์‹œ ํด๋ฆญํ•˜๋ฉด ์›๋ž˜๋Œ€๋กœ ๋Œ์•„์˜ค๋Š” ํ† ๊ธ€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด map ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด todos state์—์„œ ์ฒดํฌ๋œ ํ•ญ๋ชฉ์„ ๋ฐ˜์˜ํ•ด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค.

์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ํ™œ์šฉํ•ด ์ฒดํฌ๊ฐ€ ๋˜์—ˆ๋‹ค๋ฉด ์Šคํ”„๋ ˆ๋“œ ์—ฐ์‚ฐ์ž๋กœ ๋‚˜๋จธ์ง€ ํ•ญ๋ชฉ์€ ์œ ์ง€ํ•˜๊ณ  checked๋งŒ !todo.checked๋ฅผ ์ฃผ์—ˆ๋‹ค.


๐Ÿ” className={cn('checkbox', {checked})}

  • import cn from 'classnames';
  • ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง์„ ์ฃผ๊ธฐ ์œ„ํ•ด classNames ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ
  • {checked}๊ฐ€ true์ธ ๊ฒฝ์šฐ className="checkbox checked"๊ฐ€ ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.!

๐Ÿ“Œ CSS

  • transition: 0.3s background ease-in;
    ๋ฒ„ํŠผ ํ˜ธ๋ฒ„ ์‹œ, ๋ณด๋‹ค ๋ถ€๋“œ๋Ÿฌ์šด ํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

  • &:nth-child(even) { background-color: rgb(240, 240, 240); }
    ์ง์ˆ˜๋ฒˆ์งธ ๋ฆฌ์ŠคํŠธ๋Š” ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ์„ ํšŒ์ƒ‰์œผ๋กœ ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

  • svg { font-size: 20px; }
    react icon์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์•„์ด์ฝ˜์— className์„ ์ฃผ์—ˆ๋Š”๋ฐ ๊ทธ๋Ÿด ํ•„์š” ์—†์ด svg๋กœ ๋ช…์‹œํ•˜๋ฉด ๋œ๋‹ค!

  • & + & { border-top: 1px solid lightgray; }
    = .todoListItem + .todoListItem { border-top: 1px solid lightgray; }
    ๋ฆฌ์ŠคํŠธ ์‚ฌ์ด์— border๋ฅผ ์ค„ ๋•Œ ์‚ฌ์šฉ


๐Ÿ“† ์™„์„ฑ!


์ฐธ๊ณ ) ๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ 

0๊ฐœ์˜ ๋Œ“๊ธ€