useCustom hook์„ ๋งŒ๋“ค์–ด ์„œ๋น„์Šค ํ—ค๋”์˜ ๋’ค๋กœ๊ฐ€๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„

2025. 2. 5. 18:51ยทWhat I Learn

์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€ ๋ผ์šฐํ„ฐ๋Š” /messagebox/[userId]/[type]/[messageId]/[options] ์ธ๋ฐ, ๋งˆ์ง€๋ง‰ ๊ฒฝ๋กœ [options]๋Š” ๋ณ‘๋ ฌ ๋ผ์šฐํŒ…์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ๊ฒฝ๋กœ ๊ฐ€๋กœ์ฑ„๊ธฐ๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€ ์ƒ์œ„์— ๋„์šฐ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•œ ํŽ˜์ด์ง€์™€ ์ชฝ์ง€์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” reaction ํŽ˜์ด์ง€๊ฐ€ ์žˆ์–ด์„œ ๊ฒฝ๋กœ์— ๋งž์ถฐ ๊ธฐ๋Šฅ์„ ๊ตฌ๋ถ„ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์ฒ˜์Œ์— ๋‹จ์ˆœํžˆ router.back()์œผ๋กœ ํ•ด๊ฒฐํ•˜๋ ค ํ•˜๋‹ˆ ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ ๊ณ ๋ คํ–ˆ์„ ๋•Œ ์˜๋„ํ•œ ๋ฐ”๋กœ ๋’ค๋กœ๊ฐ€๊ธฐ๊ฐ€ ๋˜์ง€ ์•Š๋˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์„œ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋ณต์žกํ•œ ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋กœ์ง์„ ๊ด€๋ฆฌํ•˜๊ณ  ํŠน์ • ๊ฒฝ๋กœ์—์„œ ๋’ค๋กœ๊ฐ€๊ธฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์ปค์Šคํ…€ ํ›…์„ ๊ฐœ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์•„๋ž˜๋Š” router.back() ์ด์—ˆ์„ ๋•Œ ํ˜„์ƒ์ž…๋‹ˆ๋‹ค

https://youtu.be/HAXibZoU1Ak

 

 

์ด์ „ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ์–ตํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฐ€์žฅ ๋จผ์ € ์ƒ๊ฐํ•ด๋ณธ ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ 2๊ฐ€์ง€์˜€์Šต๋‹ˆ๋‹ค.

  1. document.referrer
  2. ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ

๊ทธ๋Ÿฐ๋ฐ ์ „์—ญ ์ƒํƒœ๋กœ ์ด์ „ ํŽ˜์ด์ง€์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋„๋ก ํ•˜๋ฉด ์ƒˆ๋กœ๊ณ ์นจ๋˜์—ˆ์„ ๋•Œ์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ซ์ง€ ์•Š์•˜๋Š”๋ฐ ํŠน์ • ์ƒํ™ฉ์—์„œ ์ €์žฅ๋œ ๊ฐ’๋“ค์ด ํœ˜๋ฐœ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•ด์„œ ๋จผ์ € 1๋ฒˆ์œผ๋กœ ์‹œ๋„ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

โŒ ์‹œ๋„ 1: document.referrer

๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜๊ณ  ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํŽ˜์ด์ง€๊ฐ€ ์ด๋™๋  ๋•Œ๋งˆ๋‹ค ์ด์ „๊ณผ ํ˜„์žฌ ํŽ˜์ด์ง€์˜ url๋“ค์„ ์ €์žฅํ•˜๋„๋กํ•ด์„œ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ๊ทธ ์ด์ „์˜ ํŽ˜์ด์ง€๋กœ ์ด๋™๋  ๊ฒƒ
  • ๋’ค๋กœ๊ฐ€๊ธฐ ๋˜๋ฉด ์ด๋™๋œ ์ฃผ์†Œ๋Š” ์ €์žฅ๋ชฉ๋ก์—์„œ ์‚ญ์ œ๋  ๊ฒƒ
  • /messagebox/${userId}์—์„œ ๋’ค๋กœ๊ฐ€๊ธฐ ๋˜๋ฉด ํ™ˆ ํ™”๋ฉด์œผ๋กœ ๊ฐ€๊ณ , ์ €์žฅ๋œ ๋ชฉ๋ก์ด ๋‹ค ๋‚ ์•„๊ฐˆ ๊ฒƒ
useEffect(() => {
    if (document.referrer.includes('/messagebox')) {
      console.log(prevPath) // null ๋‚˜์˜ด
      console.log(document.referrer) // ์ฒ˜์Œ ์ ‘๊ทผํ•œ url ๋‚˜์˜ด
      setPrevPath(document.referrer) 
    }
  }, [pathname])

 

useEffect๋กœ pathname์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ์ง€ํ•ด์„œ ์ดˆ๊ธฐ๊ฐ’์ด null์ธ ๋ฌธ์ž์—ด ๋ฐฐ์—ด prevPath์— url์„ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜๊ณ , ๋’ค๋กœ ๊ฐ€๊ธฐ ํ•˜๋ฉด ๋ฐฐ์—ด์—์„œ ์‚ญ์ œ๋˜๋„๋ก ํ•˜๋ฉด ํ•ด๊ฒฐ๋˜๊ฒ ๋‹ค๊ณ  ์˜ˆ์ƒํ•œ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ, prevPath๊ฐ€ null๋กœ ๊ด€์ธก๋˜์—ˆ์Šต๋‹ˆ๋‹ค. document.referrer์˜ ๋ฐ˜ํ™˜๊ฐ’ ๋˜ํ•œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ์ด์œ ๋กœ Next.js์—์„œ๋Š” ๋‚ด๋ถ€ ๋ผ์šฐํ„ฐ๋กœ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ตœ์ดˆ ์ง„์ž…ํ•œ ์ฃผ์†Œ๋งŒ ๊ฐ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์„๊นŒ ์ถ”์ธกํ–ˆ์Šต๋‹ˆ๋‹ค.

MDN ๋ฌธ์„œ์—๋Š” '๋งํฌ๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œํ‚จ, ์ „ ํŽ˜์ด์ง€์˜ URI ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค'๊ณ  ๋˜์–ด์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

โœ… ์‹œ๋„ 2: Session Storage

๋งˆ์ง€๋ง‰์œผ๋กœ, ๋ธŒ๋ผ์šฐ์ € ์›น ์Šคํ† ๋ฆฌ์ง€ ์ž์ฒด์— ์ด์ „ ์ ‘๊ทผ URL์„ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋– ์˜ฌ๋ ธ์Šต๋‹ˆ๋‹ค.

๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๋ฉด ํƒญ์„ ๋‹ซ์•„๋„ ์‚ญ์ œ๋˜์ง€ ์•Š์•„์„œ, ํƒญ์„ ๋‹ซ๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ข…๋ฃŒํ•˜๋ฉด ์•Œ์•„์„œ ํœ˜๋ฐœ๋˜๋Š” ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ๋Š” ์Šคํƒ์„ ๊ตฌํ˜„ํ•ด ์„ธ์…˜์— ์Šคํƒ ๋ฐฐ์—ด์„ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ›…์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ด์ „ ์ฃผ์†Œ๊ฐ’๊ณผ ํ˜„์žฌ ์ฃผ์†Œ๊ฐ’์ด ๊ฐ™์œผ๋ฉด ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • /messagebox/[userId]/[type]/[messageId] ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋Š” ๋ฃจํŠธ๊ฐ€ 2๊ฐ€์ง€์ธ ๊ฒƒ์„ ๊ณ ๋ คํ•œ๋‹ค.
    • ์œ„ ์ฃผ์†Œ๊ฐ€ 3๋ฒˆ์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ 3๋ฒˆ์— ๋„๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ 1-> 2 -> 3, 1 -> 3 ์ด ์žˆ๋‹ค.
  • [options]์—์„œ๋Š” /reaction ํŽ˜์ด์ง€์ธ์ง€ ๋ชจ๋‹ฌ ํŽ˜์ด์ง€์ธ์ง€์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • /[options] ๊ฒฝ๋กœ๋Š” ๋’ค๋กœ๊ฐ€๊ธฐ ์Šคํƒ์— ์ถ”๊ฐ€๋˜๋ฉด ์•ˆ๋œ๋‹ค.
    • /reaction ๋Š” POST ์š”์ฒญ์„ ํ•˜๋Š” api๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€์ธ๋ฐ, ์š”์ฒญ ํ›„ /messagebox/[userId]/[type]/[messageId] ๋กœ ์ด๋™๋˜๋Š” ๊ณผ์ •์„ ๊ณ ๋ คํ•ด์•ผํ•œ๋‹ค. ์ด๋™๋œ ํŽ˜์ด์ง€์—์„œ ๋’ค๋กœ๊ฐ€๊ธฐ๋ฅผ ํ–ˆ์„ ๋•Œ /reaction์œผ๋กœ ๋Œ์•„๊ฐ€๋ฉด ์•ˆ๋œ๋‹ค.

 

 useEffect(() => {
    const storage = globalThis?.sessionStorage
    if (!storage) return

    let pathStack = JSON.parse(storage.getItem('pathStack') || '[]')
    const pathParts = pathname.split('/')

    if (pathParts.length > 4) return
    
    ....

 

useEffect ํ›…์— userId, pathname์„ ์˜์กด์„ฑ์œผ๋กœ ์ฃผ์ž…ํ•˜๊ณ  globalThis?.sessionStorage๋ฅผ ํ†ตํ•ด ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ–ˆ๊ณ , ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์—์„œ pathStack์„ ๊ฐ€์ ธ์™€์„œ JSON ํŒŒ์‹ฑํ•˜์—ฌ ๊ธฐ์กด์˜ ๊ฒฝ๋กœ ์Šคํƒ์„ ์ดˆ๊ธฐํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

[options]๋ฅผ ์ œ์™ธํ•˜๊ณ  ๊ฒฝ๋กœ์˜ ์ตœ๋Œ€ ํŒŒํŠธ ์ˆ˜๊ฐ€ 4๊ฐœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ฆฌ์„ฑ์„ ๊ฐ•ํ™”ํ•˜๊ธฐ ์œ„ํ•ด 4๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ๋” ์ด์ƒ ๊ฒฝ๋กœ๋ฅผ ์ถ”์ ํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

    if (pathname === `/messagebox/${userId}`) {
      storage.removeItem('pathStack')
      pathStack = [pathname]
    } else if (pathStack[pathStack.length - 1] !== pathname) {
      if (pathParts.length >= 3) {
        if (!pathStack.includes(pathname)) {
          pathStack.push(pathname)
        }
      }
    }

    storage.setItem('pathStack', JSON.stringify(pathStack))
  }, [pathname, userId])

 

/messagebox ์ด์™ธ์˜ ๊ฒฝ๋กœ์—์„œ๋Š” ๋ณต์žกํ•œ ๊ฒฝ๋กœ ์ด๋™์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๊ฐ€ ํ˜„์žฌ /messagebox/[userId] ๋กœ ์ง„์ž…ํ–ˆ์„ ๋•Œ๋งŒ์˜ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ ์ด์ „ ๊ฒฝ๋กœ๋ฅผ ์ง€์šฐ๊ณ  ์ƒˆ๋กœ์šด ๊ฒฝ๋กœ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

pathStack์—์„œ ๋งˆ์ง€๋ง‰ ๊ฒฝ๋กœ๊ฐ€ ํ˜„์žฌ pathname๊ณผ ๋‹ค๋ฅด๋ฉด์„œ ์ƒˆ๋กœ์šด ๊ฒฝ๋กœ๊ฐ€ pathStack์— ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ถ”๊ฐ€๋˜๋„๋ก ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๋•Œ๋งŒ pathStack ๋ฐฐ์—ด์— pathname์„ pushํ–ˆ์Šต๋‹ˆ๋‹ค.

์ตœ์ข…์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋œ pathStack์„ ๋‹ค์‹œ ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

 

interface navProps {
  userId: string
  messageId?: string
  type?: MessageType
}

export const useBackHandler = ({ userId, type, messageId }: navProps) => {
  const router = useRouter()
  const pathname = usePathname()

  const backHandler = () => {
    const storage = globalThis?.sessionStorage
    if (!storage) return

    const pathStack = JSON.parse(storage.getItem('pathStack') || '[]')
    const pathParts = pathname.split('/')
    const lastSegment = pathParts[pathParts.length - 1]

    if (pathname === `/messagebox/${userId}`) {
      storage.removeItem('pathStack')
      router.replace(`/home/${userId}`)
      return
    }
    
    if (pathname === `/messagebox/${userId}/${type}/${messageId}`) {
      router.replace(pathStack[pathStack.length - 1])
      storage.setItem('pathStack', JSON.stringify(pathStack))
      pathStack.pop()
      return
    }
    
    if (lastSegment === 'reaction') {
      const messagePagePath = pathParts.slice(0, -1).join('/')
      router.replace(messagePagePath)
      pathStack.pop()
      return
    }

    if (pathParts.length > 4 && lastSegment !== 'reaction') {
      router.replace(pathStack[pathStack.length - 1])
      pathStack.pop()
      return
    }

    if (pathStack.length > 1) {
      pathStack.pop()
      storage.setItem('pathStack', JSON.stringify(pathStack))
      router.replace(pathStack[pathStack.length - 1])
    }
    
    router.back()
  }

{/* ์•ž์˜ useEffect */}

  return backHandler
}

 

์ด์ œ ์กฐ๊ฑด ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์คฌ๋Š”๋ฐ, ์•ž์„œ ์ •๋ฆฌํ•œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ธฐ์ค€์œผ๋กœ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋„๋ก ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

/messagebox/[userId] ์œ„์น˜์— ์žˆ์„๋•Œ ๋’ค๋กœ๊ฐ€๊ธฐ ํ•˜๋ฉด home์œผ๋กœ ๋Œ์•„๊ฐ€๊ณ , session storage์— ์ €์žฅ๋˜์–ด์žˆ๋˜ pathStack ์ž์ฒด๊ฐ€ ๋‚ ์•„๊ฐ€๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

pathStack์—๋Š” ๋ฐฐ์—ด์˜ ๋์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š” push ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ path๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•ด์„œ /messagebox/[userId]/[type]/[messageId] ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋Š” ๋ฃจํŠธ๊ฐ€ 2๊ฐ€์ง€์—ฌ๋„ ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ๊ฐ’์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋Œ€์ฒด์‹œํ‚จ ํ›„, ์‚ฌ์šฉํ•œ ๊ฐ’์„ pathStack์—์„œ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด pop ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

/messagebox ์ด์™ธ์˜ ๊ฒฝ๋กœ์—์„œ๋Š” ๋‹จ์ˆœํžˆ router.back()๋งŒ ํ•ด์ค˜๋„ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์กฐ๊ฑด์— ๋ชจ๋‘ ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด router.back()์„ ํ†ตํ•ด ๋’ค๋กœ๊ฐ€๊ธฐ๊ฐ€ ์ž‘๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ด์ œ ์‚ฌ์šฉ์ž์˜ ์˜ˆ์ƒ๋Œ€๋กœ ๋’ค๋กœ๊ฐ€๊ธฐ๋ฅผ ํ†ตํ•œ ์ด๋™์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

https://youtu.be/LRM-yF2Lxns

 

 

 

'What I Learn' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

husky์™€ GitHub Actions์„ ์‚ฌ์šฉํ•œ CICD  (2) 2025.02.05
Intersection Observer API๋ฅผ ์‚ฌ์šฉํ•ด ๋ทฐํฌํŠธ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ  (0) 2025.02.05
Next.js ๋ณ‘๋ ฌ ๋ผ์šฐํŒ… & ๊ฒฝ๋กœ ๊ฐ€๋กœ์ฑ„๊ธฐ๋ฅผ ํ†ตํ•œ ๋ชจ๋‹ฌ ํŽ˜์ด์ง€ ๊ตฌํ˜„ 2  (0) 2024.12.26
e.stopPropagation(), ์ด๋ฒคํŠธ ์ „ํŒŒ ๋ฐฉ์ง€  (0) 2024.12.10
format date as 'YYYY.MM.DD AMhh:mm'  (0) 2024.12.10
'What I Learn' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • husky์™€ GitHub Actions์„ ์‚ฌ์šฉํ•œ CICD
  • Intersection Observer API๋ฅผ ์‚ฌ์šฉํ•ด ๋ทฐํฌํŠธ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ
  • Next.js ๋ณ‘๋ ฌ ๋ผ์šฐํŒ… & ๊ฒฝ๋กœ ๊ฐ€๋กœ์ฑ„๊ธฐ๋ฅผ ํ†ตํ•œ ๋ชจ๋‹ฌ ํŽ˜์ด์ง€ ๊ตฌํ˜„ 2
  • e.stopPropagation(), ์ด๋ฒคํŠธ ์ „ํŒŒ ๋ฐฉ์ง€
nuew
nuew
๐Ÿคธ ์žฌ์ฃผ ๋„˜๋Š” ์ค‘
  • nuew
    bloggg. . .๐Ÿฆ–๐Ÿ’ฅ
    nuew
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (88)
      • issue (10)
      • baekjoon (41)
      • lecture recap (11)
      • What I Learn (26)
      • retrospective (0)
      • maeil-mail (0)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    Algorithm
    JavaScript
    issue
    js
    TailwindCSS
    TypeScript
    media-query
    Baekjoon
    ํ•œ์ž…ํฌ๊ธฐ๋กœ ์ž˜๋ผ๋จน๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ
    Study
    Node.js
    ํ•œ์ž…ํฌ๊ธฐ๋กœ์ž˜๋ผ๋จน๋Š”ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ
    ์•Œ๊ณ ๋ฆฌ์ฆ˜
    what i learn
    ์ฝ”๋”ฉํ…Œ์ŠคํŠธ
    css
    modal
    ๋ฐฑ์ค€
    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
    zustand
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
nuew
useCustom hook์„ ๋งŒ๋“ค์–ด ์„œ๋น„์Šค ํ—ค๋”์˜ ๋’ค๋กœ๊ฐ€๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”