๊ฐ๋จํ ์ผ์ ๊ด๋ฆฌ ์ฑ์ ๋ง๋ค์ด ๋ณด์๋ค.
๊ธฐ์กด์ ์ฑ์ ๊ตฌ์กฐ์ ์ปดํฌ๋ํธ๋ค์ ์ด๋ค ๋ฐฉ์์ผ๋ก ์ค๊ณํด์ผ ์ข์์ง ๊ณ ๋ฏผ์ด ๋ง์๋๋ฐ, ํํ ๋ฆฌ์ผ์ ๋ฐ๋ผ ์งํํ๋ ๊ฐ๋ ์ด ๋ณด๋ค ๋ช ํํด์ง ๊ฒ ๊ฐ์๋ค.(๋ฌผ๋ก ์ ๋ต์ ์์ง๋ง)
๊ธฐ์กด ํ๋ก์ ํธ์ ๋ฌ๋ฆฌ ์ปดํฌ๋ํธ ์ฑ๋ฅ ์ต์ ํ๋ ๊ณ ๋ฏผํด๋ณผ ์ ์๋ ๊ธฐํ์๋ค!๐ค
์ ์ฒด์ ์ผ๋ก TodoTemplate
์ปดํฌ๋ํธ๊ฐ input ์ฐฝ๊ณผ ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ธ๊ณ ์๋ ๊ตฌ์กฐ์ด๋ค. ๊ทธ๋ฆฌ๊ณ TodoTemplate.js
์์๋ ์ด๋ฅผ {children}์ผ๋ก ๋ฐ์์ค๊ณ ์๋ค.
๐ useRef ์ฌ์ฉํ ์ด์
id์ ์๋ก์ด ํญ๋ชฉ์ ๋ง๋ค๋ ์ฐธ์กฐ๋๋ ๊ฐ์ด๊ธฐ ๋๋ฌธ์ id๊ฐ ๋ฐ๋๋ค๊ณ ํด์ ๋ค์ ๋๋๋ง๋ ํ์๊ฐ ์๋ค. ๋ฐ๋ผ์ useRef๋ฅผ ์ฌ์ฉํ์ฌ ๊ด๋ฆฌํ๋ค.
๐ useCallback ์ฌ์ฉํ ์ด์
๐ ๋๋๋ง ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด!
์ปดํฌ๋ํธ๊ฐ ๋ค์ ๋๋๋ง๋ ๋๋ง๋ค ํจ์๋ฅผ ๋ง๋๋ ๊ฒ์ด ์๋๋ผ, ํ๋ฒ ํจ์๋ฅผ ๋ง๋ค๊ณ ๋ค์ ์ฌ์ฌ์ฉํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.๐ useCallback ์ฌ์ฉ๋ฒ
์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์๋ ์์ฑํ๊ณ ์ถ์ ํจ์๋ฅผ, ๋ ๋ฒ์งธ ํ๋ฆฌ๋ฏธํฐ์๋ ์ด๋ค ๊ฐ์ด ๋ฐ๋์์ ๋ ํจ์๋ฅผ ์๋ก ์์ฑํด์ผ ํ๋์ง ๋ช ์ํด์ค๋ค(์์กด์ฑ ๋ฐฐ์ด).
onInsert ํจ์์์๋ setTodos๋ฅผ ํตํด todos ๊ฐ์ด ๋ณํํ๊ธฐ ๋๋ฌธ์ ๋ฐฐ์ด์ todos๋ฅผ ๋ฃ์ด์ฃผ์๋ค.
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 ์ด๋ฒคํธ๊ฐ ๋ธ๋ผ์ฐ์ ๋ฅผ ์๋ก๊ณ ์นจ ์ํค๋ ๊ฒ์ ๋ฐฉ์งํด์ค๋ค.
App.js์์ ๋๊ฒจ์ค todos, onRemove, onToggle๋ฅผ props๋ก ๋ฐ๊ณ , map ํจ์๋ฅผ ํตํด TodoListItem ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ์คํธ๋ก ๋ง๋ค์ด์ค๋ค.
App.js์์ ๋๊ฒจ์ค onRemove, onToggle ํจ์๋ฅผ props๋ก ๋ฐ๊ณ ์๋ค.
ํด๋ฆญ๋ ํญ๋ชฉ์ id๋ฅผ ๋ฐ์ ๋ค์ setTodos๋ฅผ ํด์ค๋ค. ์ฌ๊ธฐ์ ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ๋ณํํ์ง ์๋ filter ํจ์๋ฅผ ์ฌ์ฉํด ํด๋ฆญ๋ ํญ๋ชฉ ์ด์ธ์ ๊ฒ๋ง ๋จ๊ฒจ์ค๋ค.
๋ง์ง๋ง์ผ๋ก state todos
๊ฐ ๋ณํ๋์์ ๋ ํด๋น ํจ์๊ฐ ์คํ๋ ์ ์๋๋ก ์์กด์ฑ ๋ฐฐ์ด์ todos๋ฅผ ๋ฃ์ด์ฃผ๊ณ , useCallback ํจ์๋ก ๊ฐ์ธ์ฃผ์ด ๋๋๋ง ์ฑ๋ฅ์ ์ต์ ํ ํด์ค๋ค.
์ฒดํฌํ๋ฉด ๊ฐ์ด๋ฐ ์ ์ด ์๊ธฐ๊ณ ๋ค์ ํด๋ฆญํ๋ฉด ์๋๋๋ก ๋์์ค๋ ํ ๊ธ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํด map ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ์กด todos state์์ ์ฒดํฌ๋ ํญ๋ชฉ์ ๋ฐ์ํด ์๋ก์ด ๋ฐฐ์ด์ ๋ฐํํ๋ค.
์ผํญ์ฐ์ฐ์๋ฅผ ํ์ฉํด ์ฒดํฌ๊ฐ ๋์๋ค๋ฉด ์คํ๋ ๋ ์ฐ์ฐ์๋ก ๋๋จธ์ง ํญ๋ชฉ์ ์ ์งํ๊ณ checked๋ง !todo.checked
๋ฅผ ์ฃผ์๋ค.
๐
className={cn('checkbox', {checked})}
import cn from 'classnames';
- ์กฐ๊ฑด๋ถ ์คํ์ผ๋ง์ ์ฃผ๊ธฐ ์ํด classNames ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ
- {checked}๊ฐ true์ธ ๊ฒฝ์ฐ
className="checkbox checked"
๊ฐ ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.!
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๋ฅผ ์ค ๋ ์ฌ์ฉ
์ฐธ๊ณ ) ๋ฆฌ์กํธ๋ฅผ ๋ค๋ฃจ๋ ๊ธฐ์