Vue3의 훅(Hook)详解 및 커스텀 지시문과의 결합

Vue3 커스텀 훅 기법

훅은 라이프사이클 콜백을 처리하는 함수 형태의 기능입니다. React의 훅을 차용한 Vue3의 Composition API는 복잡한 로직을 재사용 가능한 모듈로 분리할 수 있도록 설계되었습니다. 이는 Vue2의 Mixin과 유사하지만, 코드 출처가 명확하고 관리가 용이합니다.

Vue3 훅 활용 패턴

1. 커스텀 훅 파일 생성

import { onMounted } from "vue"

interface ImageOptions {
    targetSelector: string
}
export default function (config: ImageOptions): Promise<{ dataUrl: string }> {
    return new Promise((resolve) => {
        onMounted(() => {
            const imageElement = document.querySelector(config.targetSelector) as HTMLImageElement;
            imageElement.onload = () => {
                resolve({
                    dataUrl: convertToBase64(imageElement)
                })
            }
        })
        function convertToBase64(img: HTMLImageElement): string {
            const canvas = document.createElement('canvas')
            const context = canvas.getContext('2d')
            canvas.width = img.width;
            canvas.height = img.height;
            context?.drawImage(img, 0, 0, canvas.width, canvas.height)
            return canvas.toDataURL('image/png')
        }
    })
}

2. 컴포넌트에서 사용 예시

<template>
    <div>
        ![](../../assets/vue.svg)
    </div>
</template>
<script setup lang="ts">
import useImageProcessor from "../hooks/index"
useImageProcessor({
    targetSelector: "#image",
}).then((result) => {
    console.log(result.dataUrl)
})
</script>
<style scoped lang="scss"></style>


3. 결과 확인 방법

컨솔에서 base64 문자열을 추출하여 브라우저 주소창에 data:image/png;base64, 접두사를 붙여서 확인 가능

커스텀 훅 + 지시문 결합 사례

요구사항: DOM 요소 크기 변경 감지 기능을 훅과 지시문으로 구현

  1. 요소 크기 감지 기술
  2. Vite 기반 라이브러리 패키징
  3. NPM 배포 프로세스
  1. 프로젝트 생성 V-RESIZE-XM

  • 프로젝트 초기화: pnpm init으로 package.json 생성
  • 타입스크립트 설정: tsc --init으로 tsconfig.json 생성
  • Vite 설정 파일 생성: vite.config.ts
  • 타입 선언 파일: index.d.ts
  • 의존성 설치: pnpm i vue vite -D
  1. 훅 로직 구현

ResizeObserver를 활용한 요소 크기 감지 기법 MutationObserver를 통한 자식 노드 변경 감지 IntersectionObserver를 이용한 시야 내 존재 여부 확인


import type { App } from 'vue'
function useElementResize(element: HTMLElement, handler: (rect: {width: number, height: number}) => void) {
    const observer = new ResizeObserver((entries) => {
        handler(entries[0].contentRect)
    })
    observer.observe(element)
}
// 플러그인 형식으로 등록
const registerDirective = (app: App) => {
    app.directive('resize', {
        mounted(el, binding) {
            useElementResize(el, binding.value)
        }
    })
}
useElementResize.install = registerDirective
export default useElementResize

  1. 라이브러리 패키징 설정


import { defineConfig } from 'vite'
export default defineConfig({
    build: {
        lib: {
            entry: 'src/index.ts',
            name: 'elementResizer',
        },
        rollupOptions: {
            external: ['vue'],
            output: {
                globals: {
                    vue: 'Vue'
                }
            }
        }
    }
})

  1. 패키지 설정 파일 수정

{
  "name": "v-resize-xm",
  "version": "0.0.1",
  "description": "",
  "main": "dist/v-resize-xm.umd.js",
  "module": "dist/v-resize-xm.mjs",
  "scripts": {
    "build":"vite build"
  },
  "files": [
    "dist",
    "index.d.ts"
  ],
  "devDependencies": {
    "vite": "^5.2.11",
    "vue": "^3.4.26"
  }
}

  1. 사용 예시

<template>
    <div id="resizable">
        <a href="http://vitejs.dev" target="_blank">
            ![Vite logo](/vite.svg)
        </a>
    </div>
</template>
<script setup lang="ts">
import useElementResize from "v-resize-smy"
import { onMounted } from "vue"
onMounted(() => {
    useElementResize(document.querySelector("#resizable") as HTMLElement, (size) => {
        console.log(size)
    })
})
</script>
<style scoped lang="scss">
#resizable {
    border: 1px solid #ccc;
    resize: both;
    overflow: hidden;
}
img {
    width: 50px;
    height: 50px;
}
</style>

  1. 지시문과 훅 결합 사용법

<template>
    <div v-resize="handleResize" id="resizable">
        <a href="http://vitejs.dev" target="_blank">
            ![Vite logo](/vite.svg)
        </a>
    </div>
</template>
<script setup lang="ts">
const handleResize = (dimensions: {width: number, height: number}) => {
    console.log(dimensions)
}
</script>

훅 기술의 장점

  1. 별도의 모듈로 구성되어 다른 컴포넌트와 공유 가능
  2. 반응형 데이터를 포함한 상태 관리가 가능
  3. 고결합 저연결 구조로 유지보수성 향상

훅과 유틸리티 함수의 차이

공통점:

두 방법 모두 코드 재사용성을 높이고 모듈화가 가능합니다.

차이점:

  1. 구조적 차이: 훅은 컴포넌트 레벨의 로직을 추상화한 반면, 유틸리티는 순수한 함수 집합
  2. 반응성 지원: 훅은 ref/reactive 등을 통해 반응성 지원, 유틸리티는 순수 함수이므로 반응성 없음
  3. 적용 범위: 훅은 상태와 라이프사이클을 공유, 유틸리티는 단순한 작업 수행에 초점

태그: vue3 Custom Directive Hook ResizeObserver Vite

5월 28일 15:42에 게시됨