Curl Up Black Cat

๐Ÿ˜Ž ์„œ๋ก 

์•ˆ๋…•ํ•˜์„ธ์š”! ์˜ค๋Š˜์€ React Hook Form ๊ณผ useRef ์˜ ์กฐํ•ฉ์„ ํ†ตํ•ด ํŠน์ • input ์š”์†Œ์— ์ง์ ‘ ์ „๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.
์ตœ๊ทผ ๊ฒŒ์‹œํŒ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฒŒ์‹œ๊ธ€์„ ์—ด ๋•Œ ๋Œ“๊ธ€ ์ž‘์„ฑ์ž ํ•„๋“œ์— ์ž๋™์œผ๋กœ ํฌ์ปค์Šค๋ฅผ ์ฃผ๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ React Hook Form ๋„์ž… ์‹œ์— ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋‚ด์šฉ๊ณผ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿค” ๋ฌธ์ œ์ƒํ™ฉ ์™œ ref={commentAuthorInputRef} ๋กœ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š์„๊นŒ?

React Hook Form ์„ ์‚ฌ์šฉํ•  ๋•Œ, ์ฃผ์š” ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋Š” register ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” input ํ•„๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋‚˜ ํผ ์ œ์ถœ ๋“ฑ์˜ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ œ๊ฐ€ ์ฒ˜์Œ์— ์‚ฌ์šฉํ•œ ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค.

const commentAuthorInputRef = useRef(null)

...

useEffect(() => {
    commentAuthorInputRef.current.focus();
}, []);

...

<input ref={commentAuthorInputRef} ... />

๊ทธ๋Ÿฐ๋ฐ, ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด React Hook Form ์˜ register ์™€ ref ์™€ ๋™์‹œ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์•„, ์ž…๋ ฅ ๊ฐ’์ด undefined ๋กœ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
 
register ํ•จ์ˆ˜๋Š” input ํ•„๋“œ๋ฅผ ๋“ฑ๋กํ•˜๋ฉด์„œ ํ•ด๋‹น  ํ•„๋“œ์˜ ์ฐธ์กฐ ref ๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ์™ธ๋ถ€์—์„œ ๋ณ„๋„์˜ ref ๋ฅผ ์—ฐ๊ฒฐํ•  ๋•Œ๋Š”  register ์™€์˜ ์—ฐ๋™์ด ์ค‘์ฒฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋•Œ๋ฌธ์—, ๋‚ด๋ถ€์ ์œผ๋กœ ํผ ๊ฐ’์˜ ์ƒํƒœ ๊ด€๋ฆฌ๋‚˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ๋“ค์ด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


๐ŸŒŸ ํ•ด๊ฒฝ ๋ฐฉ๋ฒ•: ref ๋ฅผ ํ•จ์ˆ˜๋กœ ์ •์˜ํ•˜๊ธฐ

React Hook Form ์˜ register ํ•จ์ˆ˜๋Š” ref ์™€ ํ•จ๊ป˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์ž…๋ ฅ ์š”์†Œ์— ์—ฐ๊ฒฐํ•˜๋ฉด์„œ ๋™์‹œ์— ์™ธ๋ถ€ ref ์—๋„ ์—ฐ๊ฒฐํ•ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 <input
  {...commentRegister('author', { 
  	required: '๋Œ“๊ธ€ ์ž‘์„ฑ์ž๋Š” ํ•„์ˆ˜ ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค.' 
  })}
  ref={(e) => {
    commentRegister('author').ref(e); // react-hook-form ์„ ์œ„ํ•œ ref
    commentAuthorInputRef.current = e; // ์™ธ๋ถ€ ref
  }}
  ...
/>

์œ„ ์ฝ”๋“œ์—์„œ ์ค‘์š”ํ•œ ์ ์€ ref ํ•จ์ˆ˜๊ฐ€ ๋‘ ๊ฐ€์ง€ ์—ฐ๊ฒฐ ์ž‘์—…์„ ๋™์‹œ์— ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
1. React Hook Form ์˜ ref ์— ์š”์†Œ(HTMLInputElement)๋ฅผ ์—ฐ๊ฒฐ
2. ์™ธ๋ถ€ ref์—๋„ ๋™์ผํ•œ ์š”์†Œ(HTMLInputElement)๋ฅผ ์—ฐ๊ฒฐ
 
์ด๋ฅผ ํ†ตํ•ด React Hook Form ์˜ ๊ธฐ๋Šฅ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•˜๋ฉด์„œ๋„, ์™ธ๋ถ€์—์„œ๋„ input ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.๐Ÿคญ


๐ŸŽฌ  ๊ฒฐ๋ก 

React Hook Form ์€ ๋งค์šฐ ํŽธ๋ฆฌํ•œ ๋„๊ตฌ์ด์ง€๋งŒ, ๋•Œ๋•Œ๋กœ ๋‹ค๋ฅธ React ๊ธฐ๋Šฅ๊ณผ์˜ ์กฐํ•ฉ์ด ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜ ์†Œ๊ฐœํ•œ ๋ฐฉ์‹์€ ๊ทธ๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋„ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ, ์™ธ๋ถ€ ref์™€ ํ•จ๊ป˜ React Hook Form ์„ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•  ๋•Œ ์ด ๋ฐฉ์‹์ด ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. 
 
๊ทธ๋Ÿผ ์˜ค๋Š˜๋„ ์ฆ๊ฒ๊ฒŒ ์ฝ”๋”ฉํ•˜์„ธ์š”! ๐Ÿ˜
 


๐Ÿ˜Ž ์„œ๋ก 

์˜ค๋Š˜์€ ๋ฆฌ์•กํŠธ์—์„œ ๋™์  ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€ ๋ชจ๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ์‹œํŒ ํ™”๋ฉด์„ ๋งŒ๋“ค์–ด ๋ณด๋ฉด์„œ ๋“ฑ๋ก, ์ˆ˜์ •, ์ƒ์„ธ์˜ ํ™”๋ฉด์„ ๋‹จ ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฆฌ์•กํŠธ๋กœ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ํŽ˜์ด์ง€ ๊ฐ„์˜ ์ด๋™ ๋ฐ ๋ฐ์ดํ„ฐ์˜ ํ™œ์šฉ์„ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํšจ๊ณผ์ ์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„๊นŒ? ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ ๋™์  ๋ผ์šฐํŒ… ํ™œ์šฉ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ˜ƒ ํŽ˜์ด์ง€ ๋ชจ๋“œ์˜ ์ •์˜

๋จผ์ €, AppTypes ํŒŒ์ผ์—์„œ ํŽ˜์ด์ง€์˜ ๋ชจ๋“œ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

const AppTypes = {
  PageMode: {
    view: 'view',
    add: 'add',
    edit: 'edit',
  },
  ...
}

ํŽ˜์ด์ง€์˜ ๋ชจ๋“œ๋Š” view, add, edit ์„ธ ๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ App ์—์„œ ํ™œ์šฉ๋œ๋Š ๊ฐ ๋ชจ๋“œ ํƒ€์ž…์„ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋ฉด ํ”„๋กœ์ ํŠธ์˜ ๊ตฌ์กฐ๊ฐ€ ๋”์šฑ ๋ช…ํ™•ํ•ด์ง€๊ณ  ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.


๐ŸŒŸ ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ์˜ ํ™œ์šฉ

๋ฆฌ์•กํŠธ์—์„œ ํŽ˜์ด์ง€๊ฐ„์˜ ์ด๋™์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š” ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ๋™์  ๋ผ์šฐํŒ…์€ ๋™์ผํ•œ UI ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๋ฉด์„œ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ๋ชจ๋“œ๋ฅผ ํ™œ์šฉํ•ด ๋ผ์šฐํ„ฐ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฒฝ๋กœ์™€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ด ์ฃผ์—ˆ๋Š”๋ฐ์š”..

import { Navigate, Route, Routes } from 'react-router-dom'

const App = () => {
  return (
    <Routes>
      <Route path="/board/list" element={<LayoutWithComponent layout={EmptyLayout} component={Board} />} />
      <Route path="/board/view/:id" element={<LayoutWithComponent layout={EmptyLayout} component={BoardView} />} />
      <Route path="/board/:mode" element={<LayoutWithComponent layout={EmptyLayout} component={BoardView} />} />
      ...
    </Routes>
  )
}

/board/:mode ๊ฒฝ๋กœ์™€ ๊ฐ™์ด ๋™์  ๋ผ์šฐํŠธ ๋ฐฉ์‹์œผ๋กœ ๊ฒŒ์‹œํŒ์˜ ๋‹ค์–‘ํ•œ ๋ชจ๋“œ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋ฉด ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ์˜ ๋ณต์žก๋„๋ฅผ ์ค„์ผ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋™์  ๋ผ์šฐํŒ…์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋„˜๊ธฐ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ฝ”๋“œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

const handleAddClick = useCallback(() => {
  navigateTo(`/board/${AppTypes.PageMode.add}`)
}, [navigateTo])

const handleRowClick = useCallback((id) => {
  navigateTo(`/board/view/${id}`)
}, [navigateTo])

๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ URL์„ ๊ตฌ์„ฑํ•˜์—ฌ ํ•ด๋‹น URL ์— ๋งž๋Š” ํŽ˜์ด์ง€๋กœ ๋ผ์šฐํŒ… ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“‘ ํŽ˜์ด์ง€ ๋ชจ๋“œ ๊ด€๋ฆฌ

View ์—์„œ๋Š” ๊ฒŒ์‹œ๊ธ€์˜ ์ƒ์„ธ ๋‚ด์šฉ์„ ๋ณด์—ฌ์ฃผ๋ฉฐ, ๊ฐ๊ฐ์˜ ๋ชจ๋“œ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์•ก์…˜ ๋ฒ„ํŠผ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. useParams๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ผ์šฐํŠธ์—์„œ ํ•„์š”ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€ ์ƒํƒœ๋ฅผ ์ง€์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

const BorderView = () => {
  const { mode, id } = useParams() // mode: AppTypes.PageMode
  const [currentMode, setCurrentMode] = useState(mode || AppTypes.PageMode.view)
...
}

์ด๋ ‡๊ฒŒ ํ•  ๊ฒฝ์šฐ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•˜์—ฌ ํ˜„์žฌ ๋ชจ๋“œ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ UI ์š”์†Œ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{currentMode === AppTypes.PageMode.view && (
  <>
    <button type="button" className="list-btn" onClick={handleListClick}>๋ชฉ๋ก์œผ๋กœ</button>
    <button type="button" className="edit-btn" onClick={handleEditClick}>ํŽธ์ง‘</button>
  </>
)}

{currentMode !== AppTypes.PageMode.view && (
  ...
)}

์ด ์™ธ์—๋„ ๊ฐ ๋ชจ๋“œ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ๋“ฑ์˜ ๋™์ž‘์„ ๋ถ„๊ธฐ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const onSubmit = useCallback(async (data) => {
  const payload = {
    ...data
  }
  
  try {
    if (currentMode === AppTypes.PageMode.add) {
      await BoardService.create(payload)
      navigateTo('/board')
    }
  
    if (currentMode === AppTypes.PageMode.edit) {
      await BoardService.update(id, payload)
      navigateBack()
    }
  } catch (err) {
    handleError(err.response)
  }
}, [currentMode, id, navigateTo, navigateBack, handleError])

๐Ÿ”„ ํŽ˜์ด์ง€ ๋ชจ๋“œ ๋ณ€๊ฒฝํ•˜๊ธฐ

useState ์— ์„ ์–ธํ•œ setCurrentMode ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€์˜ ๋™์ž‘ ๋ชจ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์•ก์…˜(์˜ˆ: ํŽธ์ง‘ ๋ฒ„ํŠผ ํด๋ฆญ)์— ๋”ฐ๋ผ ๋™์ž‘ ๋ชจ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ UI๋ฅผ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const handleEditClick = useCallback((e) => {
  e.preventDefault()
  setCurrentMode(AppTypes.PageMode.edit)
}, [])

๐ŸŽฌ ๊ฒฐ๋ก 

๋ฆฌ์—‘ํŠธ ๋ผ์šฐํ„ฐ์˜ ๋™์  ๋ผ์šฐํŒ…์„ ํ™œ์šฉํ•˜๋ฉด, ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์— ๋”ฐ๋ผ ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ๊ณผ ์ƒํƒœ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ๋ชจ๋“œ์˜ ๊ด€๋ฆฌ์™€ ๋ผ์šฐํŒ…์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ดค๋Š”๋ฐ, ๋ฆฌ์—‘ํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ์ด ๊ธฐ๋ฒ•์„ ์ ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์€ ๋ฌผ๋ก , ๊ฐœ๋ฐœ์ž์˜ ์ž‘์—… ํšจ์œจ๋„ ์ƒ๋‹นํžˆ ์ฆ์ง„๋  ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ™‚


๐Ÿ˜Ž ์„œ๋ก 

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค๋ณด๋ฉด ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ผ์šฐํŒ… ๊ด€๋ จ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด React Router ์˜ useNavigate ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ณด๋‹ค ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” custom hook ์„ ๋งŒ๋“ค์–ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

import { useNavigate } from 'react-router-dom'

const useAppNavigate = () => {
  const navigate = useNavigate()

  const navigateBack = () => {
    navigate(-1)
  }

  const navigateTo = (path) => {
    navigate(path)
  }

  return { navigateBack, navigateTo }
}

export default useAppNavigate

์—ฌ๊ธฐ์„œ useAppNavigate ๋ผ๋Š” custom hook ์€ ๋‘๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

1. navigateBack: ํ˜„์žฌ ํŽ˜์ด์ง€์—์„œ ์ด์ „ ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐ€๋Š” ๊ธฐ๋Šฅ

2. navigateTo: ์›ํ•˜๋Š” ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋Šฅ

 

์ด์ œ ์ด custom hook์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿค  navigateBack ํ™œ์šฉ

๋•Œ๋ก  ์‚ฌ์šฉ์ž์—๊ฒŒ '๋’ค๋กœ๊ฐ€๊ธฐ' ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ navigateBack ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const { navigateBack } = useAppNavigate();

// '๋’ค๋กœ๊ฐ€๊ธฐ' ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰
<button onClick={navigateBack}>๋’ค๋กœ ๊ฐ€๊ธฐ</button>

 

๐Ÿฅธ navigateTo ํ™œ์šฉ

ํŠน์ • ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•˜๊ณ ์ž ํ•  ๋•Œ navigateTo ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

const { navigateTo } = useAppNavigate();

// '/profile' ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•˜๊ณ ์ž ํ•  ๋•Œ
<button onClick={() => navigateTo('/profile')}>ํ”„๋กœํ•„ ๋ณด๊ธฐ</button>

์š”์•ฝํ•˜๋ฉด React Router ์˜ useNavigate ๋Š” ๊ต‰์žฅํžˆ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ํŠน์ •ํ•œ ์‚ฌ์šฉ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์กฐ๊ธˆ ๋” ํ™•์žฅ๋œ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ ์œ„์™€ ๊ฐ™์€ custom hook ์„ ํ™œ์šฉํ•˜๋ฉด ๋ณด๋‹ค ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ผ์šฐํŒ… ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿค” ์™œ Custom Hooks ์„ ๋งŒ๋“ค์—ˆ๋Š”๊ฐ€?

useNavigate ์™€ ๊ฐ™์€ ๊ธฐ๋ณธ Hooks ๊ฐ€ ์žˆ๋‹ค๋ฉด, ์™œ ์ถ”๊ฐ€์ ์œผ๋กœ custom Hooks ๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”์ง€ ๊ถ๊ธˆํ• ์ง€๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

1. ์ฝ”๋“œ ๊ฐ„๊ฒฐํ™”: ๋ฐ˜๋ณต๋˜๋Š” ๋ผ์šฐํŒ… ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ๋ช…ํ™•์„ฑ: ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ ํ†ตํ•ด ์šฉ๋„๋ฅผ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด, navigateBack ์€ ๋ฐ”๋กœ ๋’ค๋กœ ๊ฐ€๋Š” ๊ธฐ๋Šฅ์ž„์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ์œ ์—ฐ์„ฑ: ๋‚˜์ค‘์— ๋ผ์šฐํŒ… ๊ด€๋ จ ๋กœ์ง์„ ๋ณ€๊ฒฝํ•  ๋•Œ, ํ•œ ๊ณณ์—์„œ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ๊ด€๋ฆฌ๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค.

4. ์žฌ์‚ฌ์šฉ: ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ™์€ ๋กœ์ง์„ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿคญ ๊ฒฐ๋ก 

Custom Hooks ๋Š” ํ”„๋กœ์ ํŠธ์˜ ํšจ์œจ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š” ํ•ต์‹ฌ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ค„์ด๋ฉฐ, ๋ผ์šฐํŒ…๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๋” ๋ช…ํ™•ํ•˜๊ณ  ์ง๊ด€์ ์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ์˜ ๊ด€๋ฆฌ์™€ ์ˆ˜์ •์„ ์‰ฝ๊ฒŒ ํ•˜๋ฉฐ, ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ณ  ํ™œ์šฉํ•˜๋Š” ๋ฐ์—๋„ ํฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŒ…์€ "๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ " ์„œ์ ์„ ํ•™์Šตํ•˜๋ฉฐ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์™œ ๋ฆฌ์•กํŠธ์ธ๊ฐ€?

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

์ด์— ํŽ˜์ด์Šค๋ถ ๊ฐœ๋ฐœํŒ€์€ ์•„์ด๋””์–ด๋ฅผ ๊ณ ์•ˆํ•ด ๋ƒˆ์Šต๋‹ˆ๋‹ค.

 

์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค ์–ด๋–ค ๋ณ€ํ™”๋ฅผ ์ค„์ง€ ๊ณ ๋ฏผํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ๊ธฐ์กด ๋ทฐ๋ฅผ ๋‚ ๋ ค ๋ฒ„๋ฆฌ๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ์ƒˆ๋กœ ๋ Œ๋”๋ง ํ•œ๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๊ฒŒ๋˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์กฐ๊ฐ€ ๋งค์šฐ ๊ฐ„๋‹จํ•ด์ง€๊ณ , ์ž‘์„ฑํ•ด์•ผ ํ•  ์ฝ”๋“œ์–‘์ด ๋งŽ์ด ์ค„์–ด ๋“ค๋ฉฐ, ๋” ์ด์ƒ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™”๋ฅผ ์ค„์ง€ ์‹ ๊ฒฝ ์“ธ ํ•„์š”๊ฐ€ ์—†๊ณ , ๊ทธ์ € ๋ทฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ธธ์ง€ ์„ ์–ธ๋งŒ ํ•˜๋ฉด ๋˜๋ฉฐ, ๋ฐ์ดํ„ฐ ๋ณ€ํ™”๊ฐ€ ์žˆ์œผ๋ฉด ๊ธฐ์กด์— ์žˆ๋˜ ๊ฒƒ์„ ๋ฒ„๋ฆฌ๊ณ  ์ƒˆ๋กœ ๋ Œ๋”๋ง ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

ํŽ˜์ด์Šค๋ถ ๊ฐœ๋ฐœ ํŒ€์€ ์ด๋Ÿฐ ๋ฐฉ์‹์„ ์ฑ„ํƒํ•˜์—ฌ ์ตœ๋Œ€ํ•œ ์„ฑ๋Šฅ์„ ์•„๋ผ๊ณ  ํŽธ์•ˆํ•œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(user experience)์„ ์ œ๊ณตํ•˜๋ฉด์„œ ๊ตฌํ˜„ํ•˜๊ณ ์ž ๊ฐœ๋ฐœํ•œ ๊ฒƒ์ด ๋ฆฌ์•กํŠธ(React) ์ž…๋‹ˆ๋‹ค.

 

๋ฆฌ์•กํŠธ์˜ ์ดํ•ด

์ด๋ฏธ์ง€์ถœ์ฒ˜: reactjs

๋ฆฌ์•กํŠธ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ์„œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ฆฌ ๊ตฌ์กฐ๊ฐ€ MVC, MVW ๋“ฑ์ธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋‹ฌ๋ฆฌ ์˜ค์ง V(View)๋งŒ ์‹ ๊ฒฝ ์“ฐ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.

 

๋ฆฌ์•กํŠธ์—์„œ๋Š” ํŠน์ • ๋ถ€๋ถ„์ด ์–ด๋–ป๊ฒŒ ์ƒ๊ธธ์ง€ ์ •ํ•˜๋Š” ์„ ์–ธ์ฒด๊ฐ€ ์žˆ๋Š”๋ฐ ์ด๋ฅผ ์ปดํฌ๋„ŒํŠธ(component) ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ API ๋กœ ์ˆ˜๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์„ ๋‚ด์žฅํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜์—์„œ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒ๊น€์ƒˆ์™€ ์ž‘๋™ ๋ฐฉ์‹์„ ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ ์‚ฌ์šฉ์ž ํ™”๋ฉด์— ๋ทฐ๋ฅผ ๋ณด์—ฌ ์ฃผ๋Š” ๊ฒƒ์„ ๋ Œ๋”๋ง์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ทฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ Œ๋”๋งํ•˜๊ธธ๋ž˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กญ๊ฒŒ ๋ฆฌ๋ Œ๋”๋ง ํ•˜๋ฉด์„œ ์„ฑ๋Šฅ์„ ์•„๋ผ๊ณ , ์ตœ์ ์˜ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณต ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? ์ด๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด '์ดˆ๊ธฐ๋ Œ๋”๋ง'๊ณผ '๋ฆฌ๋ Œ๋”๋ง' ๊ฐœ๋…์„ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

1) ์ดˆ๊ธฐ ๋ Œ๋”๋ง

์ปดํฌ๋„ŒํŠธ์˜ render ํ•จ์ˆ˜๋ฅผ ํ†ตํ•˜์—ฌ ๋ Œ๋”๋ง์ด ์ด๋ฃจ์–ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋ Œ๋”ํ•จ์ˆ˜๋Š” ๋ทฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๊ณ  ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ง€๋‹Œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. render ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰ํ•˜๋ฉด ๋ Œ๋”๋ง์ด ์ด๋ฃจ์–ด์ง€๊ณ  HTML ๋งˆํฌ์—…(markup) ์„ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ DOM ์š”์†Œ ์•ˆ์— ์ฃผ์ž…ํ•˜๋Š” ์ž‘์—…์ด ์ด๋ฃจ์–ด ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

2) ๋ฆฌ๋ Œ๋”๋ง(์กฐํ™” ๊ณผ์ •)

๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธ ํ• ์ ์— "์—…๋ฐ์ดํŠธ ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค" ๋ผ๊ณ  ํ•˜๊ธฐ๋ณด๋‹ค "์กฐํ™” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค" ๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ •ํ™•ํ•œ ํ‘œํ˜„์ž…๋‹ˆ๋‹ค. ์ด์œ ๋Š” ์ƒˆ๋กœ์šด DOM ์š”์†Œ๋กœ ๊ฐˆ์•„ ๋ผ์šฐ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด render ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๊ณง๋ฐ”๋กœ DOM ์— ๋ฐ˜์˜ํ•˜์ง€ ์•Š๊ณ , ์ด์ „์— render ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“ค์—ˆ๋˜ ์ปดํฌ๋„ŒํŠธ ์ •๋ณด์™€ ํ˜„์žฌ render ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ ์ •๋ณด๋ฅผ ๋น„๊ตํ•œํ›„ DOM ํŠธ๋ฆฌ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๋ฆฌ์•กํŠธ์˜ ํŠน์ง•

๋ฆฌ์•กํŠธ์˜ ์ฃผ์š” ํŠน์ง• ์ค‘ ํ•˜๋‚˜๋Š” Virtual DOM์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ

 

์šฐ์„  DOM ์ด ๋ฌด์—‡์ธ์ง€ ๋ถ€ํ„ฐ ์•Œ์•„๋ณด๋ฉด.. DOM ์ด๋ž€ ๋ฌธ์„œ๊ฐ์ฒด ๋ชจ๋ธ(Document Object Model)์˜ ์•ฝ์–ด์ž…๋‹ˆ๋‹ค. ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” DOM ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ์ฒด์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ CSS ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DOM ์€ ํŠธ๋ฆฌํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”๋ฐ DOM ์„ ํ†ตํ•ด์„œ ํŠน์ • ๋…ธ๋“œ๋ฅผ ์ฐพ๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š” ๊ณณ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋ฏธ์ง€์ถœ์ฒ˜: ์œ„ํ‚ค๋ฐฑ๊ณผ

DOM ์€ ๊ณผ์—ฐ ๋Š๋ฆด๊นŒ?

DOM ์—๋Š” ์น˜๋ช…์ ์ธ ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ ๋™์  UI์— ์ตœ์ ํ™”๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

"์š”์ฆˆ์Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ๋งค์šฐ ๋น ๋ฅธ ๋ฐ˜๋ฉด, DOM ์€ ๋Š๋ฆฌ๋‹ค?" ๋ผ๊ณ  ํ•˜๋Š”๋ฐ ์ด๋Š” ์ •ํ™•ํ•œ ๋ง์ด ์•„๋‹™๋‹ˆ๋‹ค.

DOM ์ž์ฒด๋Š” ๋น ๋ฆ…๋‹ˆ๋‹ค. ๋‹จ ์›น ๋ธŒ๋ผ์šฐ์ € ๋‹จ์—์„œ DOM ์— ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚˜๋ฉด ์›น๋ธŒ๋ผ์šฐ์ €๊ฐ€ CSS๋ฅผ ๋‹ค์‹œ ์—ฐ์‚ฐํ•˜๊ณ , ๋ ˆ์ด์•„์›ƒ์„ ๊ตฌ์„ฑํ•˜๊ณ , ํŽ˜์ด์ง€๋ฅผ ๋ฆฌํŽ˜์ธํŠธํ•˜๊ฒŒ๋˜๋Š”๋ฐ ์ด ๊ณผ์ •์—์„œ ์‹œ๊ฐ„์ด ํ—ˆ๋น„๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ํ•ด๊ฒฐ๋ฒ•์œผ๋กœ DOM์„ ์ตœ์†Œํ•œ์œผ๋กœ ์กฐ์ž‘ํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Virtual DOM

์ด๋ฏธ์ง€์ถœ์ฒ˜:&nbsp;speakerdeck

๋ฆฌ์•กํŠธ๋Š” Virtual DOM ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ DOM ์—…๋ฐ์ดํŠธ๋ฅผ ์ถ”์ƒํ™”ํ•จ์œผ๋กœ์จ DOM ์ฒ˜๋ฆฌ ํšŸ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Virtual DOM ์„ ์‚ฌ์šฉํ•˜๋ฉด ์‹ค์ œ DOM์— ์ ‘๊ทผํ•˜์—ฌ ์กฐ์ž‘ํ•˜๋Š” ๋Œ€์‹ , ์ด๋ฅผ ์ถ”์ƒํ™”ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋งˆ์น˜ ์‹ค์ œ DOM์˜ ๊ฐ€๋ฒผ์šด ์‚ฌ๋ณธ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค..

 

๋ฆฌ์•กํŠธ์—์„œ ์‹ค์ œ DOM์„ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ ์„ธ๊ฐ€์ง€ ์ ˆ์ฐจ๋ฅผ ๋ฐŸ๊ฒŒ ๋˜๋Š”๋ฐ ์‚ดํŽด๋ณด๋ฉด..

1. ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ์ „์ฒด UI๋ฅผ Virtual DOM์— ๋ฆฌ๋ Œ๋”๋ง ํ•œ๋‹ค.

2. ์ด์ „ Virtual DOM์— ์žˆ๋˜ ๋‚ด์šฉ๊ณผ ํ˜„์žฌ ๋‚ด์šฉ์„ ๋น„๊ตํ•œ๋‹ค.

3. ๋ฐ”๋€ ๋ถ€๋ถ„๋งŒ ์‹ค์ œ DOM์— ์ ์šฉํ•œ๋‹ค.

 

์ด์ฒ˜๋Ÿผ  ๋ฆฌ์•กํŠธ๋Š” Virtual DOM ์„ ํ†ตํ•ด์„œ ๋™์  UI ์ตœ์ ํ™” ๋ฌธ์ œ๋ฅผ๊ฐ€์ง€๊ณ  ์žˆ๋Š” DOM ์—…๋ฐ์ดํŠธ ๋ฐฉ์‹์„ ๋ณด์•ˆํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํšจ์œจ์ ์œผ๋กœ ์ž‘์—…์„ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋˜ํ•œ ์ผ๋ถ€ ์›น ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ MVC, MVW ๋“ฑ์˜ ๊ตฌ์กฐ๋ฅผ ์ง€ํ–ฅํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ ๋ฆฌ์• ํŠธ๋Š” ์˜ค์ง ๋ทฐ๋งŒ ๋‹ด๋‹นํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ์„œ ์ทจํ–ฅ๋Œ€๋กœ ์Šคํƒ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ ‘ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐœ๋‹จ

React ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉํ•˜๋ ค๊ณ  ์„ ํƒํ•œ html ํ…œํ”Œ๋ฆฟ์— ์Šคํƒ€์ผ์„ ์‚ดํŽด๋ณด๋‹ˆ ์ผ๋ฐ˜ css ์™€ sass 2๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ์ง€์›ํ•˜์˜€๋‹ค.

sass๋กœ ์ ์šฉํ•˜๊ณ  ์‹ถ์–ด ๋ณ„๋„์˜ loader๋ฅผ ์„ค์น˜ ํ•œ ์ดํ›„ ๋นŒ๋“œ ํ•˜๋‹ˆ๊น ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

(typescript ํŒจํ‚ค์ง€ @types/node-sass ๊ฐ€ node-sass ํŒจํ‚ค์ง€๋ฅผ ์˜์กดํ•˜์—ฌ ๊ฐ™์ด ์„ค์น˜)

$ yarn add node-sass @types/node-sass

 

์›์ธ

node-sass ๋ฒ„์ „ ์ถฉ๋Œ ์ด์Šˆ

์„ค์น˜๋œ ํŒจํ‚ค์ง€์˜ ๋ฒ„์ „์„ ์‚ดํŽด๋ณด๋‹ˆ sass ๋Š” 6๋ฒ„์ „, @types sass ๋Š” 4๋ฒ„์ „์ด ์„ค์น˜๋˜์–ด์žˆ๋‹ค.

@type node-sass ํŒจํ‚ค์ง€๊ฐ€ node-sass 4.x.x, 5.x.x ๋ฒ„์ „๊นŒ์ง€๋งŒ ํ˜ธํ™˜๋˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

 

stackoverflow: https://stackoverflow.com/questions/64625050/error-node-sass-version-5-0-0-is-incompatible-with-4-0-0

 

Error: Node Sass version 5.0.0 is incompatible with ^4.0.0

I've created a blank React project, using the command: npx create-react-app on npm v7.0.7 and Node v15.0.1 Installed: React v17.0.1, node-sass v5.0.0, Then I tried to import blank .scss file to App

stackoverflow.com

 

ํ•ด๊ฒฐ

์„ค์น˜๋œ ํŒจํ‚ค์ง€๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋ฒ„์ „์„ ์ง€์ •ํ•˜์—ฌ ์„ค์น˜

$ yarn add node-sass@4.14.0 @types/node-sass@4.11.2

์ถœ์ฒ˜: https://reactrouter.com/web/guides/quick-start

๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ๋Š” ๋ฆฌ์•กํŠธ์˜ ํ™”๋ฉด ์ „ํ™˜์„ ๋„์™€์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์›น์—์„œ a ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•ด ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ–ˆ์—ˆ๋‹ค๋ฉด, ๋ฆฌ์•กํŠธ์—์„œ๋Š” React-Router๋ฅผ ํ†ตํ•ด Link ์ปดํ”„๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™”๋ฉด์„ ์ „ํ™˜ํ•œ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋งŒ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ํšจ์œจ์ ์œผ๋กœ ์„ฑ๋Šฅ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋กœ ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ๊ตณ์ด ํ™”๋ฉด ์ „์ฒด๋ฅผ ์ƒˆ๋กœ ๊ณ ์นจ ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

a ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ํŽ˜์ด์ง€๋ฅผ ์•„์˜ˆ ์ƒˆ๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋˜๋ฏ€๋กœ ๋ฆฌ์•กํŠธ ์•ฑ์ด ์ง€๋‹ˆ๊ณ  ์žˆ๋Š” ์ƒํƒœ๋“ค๋„ ๋ชจ๋‘ ์ดˆ๊ธฐํ™”๋˜๊ณ  ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ๋กœ ๋ Œ๋”๋ง ๋œ๋‹ค.

๋ฆฌ์•กํŠธ์—์„œ๋Š” SPA ํŠน์ง•์„ ์ž˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด React Router๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ถœ์ฒ˜: https://create-react-app.dev/

Create React App ์ด๋ž€?

create-react-app ์€ ํŽ˜์ด์Šค๋ถ์—์„œ ๋งŒ๋“  react ์›น ๊ฐœ๋ฐœ์šฉ boilerplate์ž…๋‹ˆ๋‹ค. react๋Š” es6 ๋ฒ„์ „์˜ javascript๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜ํ™”๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— webpack์ด๋ผ๋Š” ๋ชจ๋“ˆ ๋ฒˆ๋“ค๋Ÿฌ๋กœ ์ปดํŒŒ์ผ ๋ฐ ๋นŒ๋“œ ํ•˜๋Š” ๊ฒƒ์ด ํ•„์ˆ˜๋ผ ์ด ํ™˜๊ฒฝ์„ ์„ธํŒ…ํ•ด ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ง์ ‘ ๋ชจ๋“  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์„ค์ •ํ•˜์ง€ ์•Š์•„๋„ ํŽ˜์ด์Šค๋ถ์ด๋ผ๋Š” ๊ฑฐ๋Œ€ํ•œ ๊ธฐ์—…์—์„œ ์ง€์†์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•ด์ฃผ๊ณ  ์žˆ๊ณ  ์‰ฝ๊ฒŒ ํ”„๋กœ์ ํŠธ ๊ธฐ๋ณธ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์„ค์น˜

- js

yarn create react-app my-app

- typescript

yarn create react-app my-app --template typescript

 

์ถœ์ฒ˜: https://webpack.js.org/

Webpack ์ด๋ž€?

์›นํŒฉ(webpack) ์€ ์›น์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋“  ์ž์›(assets) ์„ ๋ฒˆ๋“ค๋ง ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋ฒˆ๋“ค๋ง์˜ ๊ฐœ๋…์€ ์—ฌ๋Ÿฌ๊ฐœ ์˜ ํŒŒ์ผ ์ค‘์— ์ข…์†์„ฑ์ด ์กด์žฌํ•˜๋Š” ํŒŒ์ผ์„ ํ•˜๋‚˜์˜ ํŒŒ์ผ๋กœ ๋ฌถ์–ด ํŒจํ‚ค์ง•์„ ์‹œํ‚ค๋Š” ๊ณผ์ •์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์›นํŒฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ„์˜ ์ข…์†์„ฑ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ ํ•„์š”ํ•œ css๋‚˜ img์™€ ๊ฐ™์€ ํŒŒ์ผ(.css, .jpg)๋„ ๋ฒˆ๋“ค๋ง ํ•ด์„œ ํ•˜๋‚˜์˜ ํŒŒ์ผ๋กœ ํ•ฉ์ณ์ค˜์„œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ตœ์†Œํ™”์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์›นํŒฉ์€ ๋…ธ๋“œ ๋ชจ๋“ˆ ์ค‘์— ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์›นํŒฉ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Node.js ๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์„ค์น˜

yarn add webpack

 

 

์ถœ์ฒ˜: https://www.ryadel.com/en/yarn-vs-npm-pnpm-2019/

NPM ์ด๋ž€?

NPM ์€ Node Packaged Manager์˜ ์•ฝ์ž์ž…๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €์ด๊ณ  Node.js์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“ˆ๋“ค์„ ํŒจํ‚ค์ง€ํ™”ํ•˜์—ฌ ๋ชจ์•„๋‘” ์ €์žฅ์†Œ ์—ญํ• ์„ ํ•˜๋ฉฐ ์„ค์น˜/๊ด€๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” CLI๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

Yarn ์ด๋ž€?

Yarn ๋„ ์—ญ์‹œ ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ์ž ์—ญํ• ์„ ํ•˜๋Š” ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์Šค๋ถ์—์„œ ๋งŒ๋“  ๊ฒƒ์œผ๋กœ npm ์„œ๋ฒ„์— ๋น„ํ•ด ์†๋„๊ฐ€ ๋น ๋ฅด๊ณ  npm ๊ณผ ์‚ฌ์šฉ๋ฒ•์ด ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. 

 

Reference: https://javascript.plainenglish.io/npm-vs-yarn-choosing-the-right-package-manager-a5f04256a93f

 

npm vs Yarnโ€Š—โ€ŠChoosing the right package manager

Choose the right package manager for your project

javascript.plainenglish.io

 

npm vs Yarn ๋ช…๋ น์–ด

์ถœ์ฒ˜: https://www.digitalocean.com/community/tutorials/nodejs-npm-yarn-cheatsheet

 

package manager (package-lock.json, yarn.lock)

๋ฆฌ์•กํŠธ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉฐ ์ž์ฃผ ๋ณผ ์ˆ˜ ์žˆ๋Š” npm ์„ ์ด์šฉํ•˜๋ฉด package-lock.json, yarn ์„ ์‚ฌ์šฉํ•˜๋ฉด yarn.lock ํŒŒ์ผ์€ ์™œ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฑธ๊นŒ์š”?

 

ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด npm์„ ์‚ฌ์šฉํ•˜๋“  yarn์„ ์‚ฌ์šฉํ•˜๋“  ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ ๋ฉ”ํƒ€ ์ •๋ณด๋Š” package.json ํŒŒ์ผ์„ ํ†ตํ•ด ๊ด€๋ฆฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด package.json ํŒŒ์ผ์—๋Š” ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๊ฐ€ ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๋ชจ๋“  ํŒจํ‚ค์ง€ ์ด๋ฆ„๊ณผ ๋ฒ„์ „์ด ๋‚˜์—ด๋˜์–ด ์žˆ๋Š”๋ฐ์š”.

์ผ๋ฐ˜์ ์œผ๋กœ ์“ฐ์ด๋Š” ํŒจํ‚ค์ง€๋“ค์€ dependencies ํ•ญ๋ชฉ์— ๋ช…์‹œ๋˜๊ณ  ๊ฐœ๋ฐœํ•  ๋•Œ๋งŒ ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์€ devDependencies ํ•ญ๋ชฉ์— ๋ช…์‹œ๋ฉ๋‹ˆ๋‹ค.

 

๊ฐœ๋ฐœ์ž๊ฐ€ ์—ฌ๋ ค ๋ช…์ด ์žˆ๋Š” ๊ฐœ๋ฐœํŒ€์—์„œ ํ”„๋กœ์ ํŠธ์— ํˆฌ์ž…๋˜๋Š” ์‹œ๊ฐ„์ด ๋‹ค๋ฅด๋‹ค๋ฉด ๊ฐ๊ฐ ์‚ฌ์šฉํ•˜๋Š” ์„ค์น˜ ๋ฒ„์ „์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด๋ ‡๊ฒŒ ๋œ๋‹ค๋ฉด ๊ฐœ๋ฐœ์ž A๋Š” ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž B์—๊ฒŒ์„œ๋Š” ์ž‘๋™์ด ์•ˆ ๋˜๋Š” ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์€ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €์—๊ฒŒ ํŒจํ‚ค์ง€ ์ž ๊ธˆ์ด ์ง€์›๋˜์ง€ ์•Š๋˜ ์‹œ์ ˆ์— ๋งค์šฐ ๊ณจ์นซ๊ฑฐ๋ฆฌ์˜€๋˜ ๋ฌธ์ œ์˜€์œผ๋ฉฐ ์ด๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ํŒจํ‚ค์ง€ ์ž ๊ธˆ์ด ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

package-lock.json์ด๋‚˜ yarn.lock ๊ณผ ๊ฐ™์€ ํŒจํ‚ค์ง€ ์ž ๊ธˆ ํŒŒ์ผ์—๋Š” ํ”„๋กœ์ ํŠธ์— ํŒจํ‚ค์ง€์— ์ตœ์ดˆ๋กœ ์ถ”๊ฐ€๋  ๋‹น์‹œ์— ๋ฒ„์ „์ด ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. ํ•จ๊ป˜ ๊ฐœ๋ฐœํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ํŒจํ‚ค์ง€ ์ž ๊ธˆ ์—ญํ• ์€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ดˆ์— setup ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ git์— ํŒจํ‚ค์ง€ ์ž ๊ธˆ ํŒŒ์ผ์„ ๋ฐ˜๋“œ์‹œ ์˜ฌ๋ ค์„œ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ํŒจํ‚ค์ง€๊ฐ€ ๊ผฌ์ด์ง€ ์•Š๋„๋ก ์‹ ๊ฒฝ ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

+ Recent posts