VueUseとは、Vue 3のComposition APIで使える便利な関数(composable)を200以上まとめたライブラリです。 useLocalStorage で入力内容をブラウザに保存する、onClickOutside でメニューの外側クリックを検知する、useDark でダークモードを切り替える、といった「きちんと書くと意外に長い処理」を1行で呼び出せます。

この記事では、2026年9月16日に公開された VueUse 15.0.0(@vueuse/core) と Vue 3.5.43、Vite 8.3.1 の組み合わせで、よく使う30関数をカテゴリ別の早見表とコピペで動くコードにまとめました。さらに上位記事にはない次の3点を、実際に動かした結果つきで載せています。

  • 関数を1つ使うごとにバンドルが何バイト増えるかをViteでビルドして実測(tree-shakingが効くことの確認と、自作との比較)
  • Chromium(Playwright)で画面を操作して、onClickOutside・useLocalStorage・useDark などの動きを確認
  • v15の変更点(useNow の更新間隔の指定方法など)と、SSR・Nuxtでの注意点

VueUseのよく使う関数 早見表(30選)

「公式カテゴリ」は VueUse のドキュメントでの分類です。すべて import { 関数名 } from '@vueuse/core' で読み込めます。

やりたいこと 関数 公式カテゴリ 最小コード
localStorageに保存・復元 useLocalStorage State const memo = useLocalStorage('memo', '')
sessionStorageなど保存先を選ぶ useStorage State useStorage('k', {}, sessionStorage)
元に戻す・やり直す useRefHistory State const { undo, redo } = useRefHistory(text)
composableを全体で1つだけ共有 createSharedComposable State export const useSharedMouse = createSharedComposable(useMouse)
要素の幅・高さを知る useElementSize Elements const { width, height } = useElementSize(el)
要素が画面に入ったら処理 useIntersectionObserver Elements useIntersectionObserver(el, ([e]) => {...})
要素が見えているかを真偽値で useElementVisibility Elements const visible = useElementVisibility(el)
ウィンドウの幅・高さ useWindowSize Elements const { width } = useWindowSize()
クリップボードにコピー useClipboard Browser const { copy, copied } = useClipboard()
タブのタイトルを変える useTitle Browser const title = useTitle('一覧')
ダークモード切り替え useDark Browser const isDark = useDark()
メディアクエリの判定 useMediaQuery Browser useMediaQuery('(min-width: 768px)')
ブレークポイントで判定 useBreakpoints Browser useBreakpoints(breakpointsTailwind).greaterOrEqual('md')
イベントを登録(自動で解除) useEventListener Browser useEventListener(window, 'resize', fn)
マウス座標 useMouse Sensors const { x, y } = useMouse()
要素の外側クリックを検知 onClickOutside Sensors onClickOutside(menu, () => { open.value = false })
スクロール位置・端に着いたか useScroll Sensors const { y, arrivedState } = useScroll(el)
キー入力を検知 onKeyStroke Sensors onKeyStroke('Escape', () => {...})
無限スクロール useInfiniteScroll Sensors useInfiniteScroll(el, loadMore, { distance: 10 })
オンライン/オフライン useOnline Sensors const online = useOnline()
APIを呼ぶ(状態つき) useFetch Network const { data, error } = useFetch(url).json()
true/falseを切り替え useToggle Utilities const [open, toggle] = useToggle()
関数を間引く(最後の1回だけ) useDebounceFn Utilities const search = useDebounceFn(fn, 300)
関数を一定間隔に制限 useThrottleFn Utilities const onScroll = useThrottleFn(fn, 200)
値の変化を遅らせたrefを作る refDebounced Reactivity const debounced = refDebounced(keyword, 300)
値の変化を間引いてwatch watchDebounced Watch watchDebounced(keyword, fn, { debounce: 300 })
一定間隔で処理(止める・再開) useIntervalFn Animation const { pause, resume } = useIntervalFn(fn, 1000)
現在時刻をリアクティブに useNow Animation const now = useNow()
日付を書式化 useDateFormat Time useDateFormat(date, 'YYYY/MM/DD')
「5分前」の表示 useTimeAgo / useTimeAgoIntl Time useTimeAgoIntl(date, { locale: 'ja' })

迷ったら「保存は State、DOM要素は Elements、ブラウザ機能は Browser、ユーザー操作は Sensors」と覚えると探しやすくなります。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「VueUseの使い方|よく使う30関数の早見表とサイズ実測【v15】」

VueUseを使う準備(インストールと前提)

VueUseはnpmでインストールし、使う関数だけを名前付きimportで読み込みます。

npm create vite@latest my-app -- --template vue
cd my-app
npm i @vueuse/core
<script setup>
import { useMouse } from '@vueuse/core'
const { x, y } = useMouse()
</script>

<template>
  <p>マウス座標: {{ x }}, {{ y }}</p>
</template>

今回の検証環境は次のとおりです。

項目 バージョン
@vueuse/core 15.0.0(2026-09-16公開)
vue 3.5.43
vite / @vitejs/plugin-vue 8.3.1 / 6.0.9
Node.js 22.22.2
ブラウザ Chromium(Playwright経由)

この記事の vue コードブロック(11個)は、すべて上の環境でビルドし、Chromiumで表示して警告・エラーが出ないことを確認しています。 「実行結果」として載せた出力は、Playwrightで実際に操作して得たものです。

前提条件は「Vue 3.5以上」と「Node.js 22以上(ビルド環境)」です。 npmに登録された @vueuse/core@15.0.0 の peerDependencies は vue: ^3.5.0、engines は node: >=22 でした。

Vue 2のプロジェクトで使う場合

VueUse 12.0以降はVue 3専用です。 公式ガイドには「Vue 2をサポートするにはv11.xを使う」と案内されています。Vue 2(2.7)のプロジェクトは長く現場を支えてきた実績があり、すぐに移行しない判断にも、安定稼働や改修コストといった理由があります。その場合は VueUse 11系を固定して使うと、Composition APIの恩恵を受けながら今の環境を保てます。

v15(2026年9月)の変更点

v14からv15への変更は「使い方が変わる箇所が少しある」程度です。 GitHubのリリースノートに載っている破壊的変更は次のとおりです。

変更 内容 対応
templateRef の削除 テンプレート参照用の関数がなくなった Vue 3.5の useTemplateRef を使う
Node.js 20のサポート終了 ビルド環境のNode要件が上がった Node.js 22以上にする
タイマー系の非推奨オプション削除 useNow などの更新間隔は scheduler で指定 下のコード例を参照
useThrottleFn の既定値 trailing の既定が false → true 最後の1回を実行したくないなら useThrottleFn(fn, 500, false)
useEventSource / useIDBKeyval SSEの受信処理、タブ間同期の動作が変わった 使っている場合はリリースノートで確認

v14(2025年10月)では、Vue 3.5以上が必須になり、別名(alias)でのexportが非推奨になっています。v13以前から上げる場合はv14の変更点もあわせて確認します。

useNowの更新間隔は scheduler で指定する

useNow は既定で requestAnimationFrame ごと(画面の描画ごと)に更新されます。1秒ごとでよい場合は、scheduler に useIntervalFn を渡します。

<script setup>
import { useNow, useIntervalFn, useDateFormat } from '@vueuse/core'

// 1秒ごとに現在時刻を更新する(v15の書き方)
const now = useNow({ scheduler: (cb) => useIntervalFn(cb, 1000) })
const label = useDateFormat(now, 'HH:mm:ss')
</script>

<template>
  <p>{{ label }}</p>
</template>

Chromiumで3.5秒待った結果、更新回数は3回でした(1秒ごとに更新されている)。

カテゴリ別:コピペで使えるコード例

State:入力内容を保存する(useLocalStorage / useStorage)

useLocalStorage は、refと同じ感覚で使えて、値を変えると自動でlocalStorageに保存されます。 初期値の型(文字列・数値・オブジェクトなど)を見て、保存時の変換(JSONへの変換など)も自動で選ばれます。

<script setup>
import { useLocalStorage, useStorage } from '@vueuse/core'

const memo = useLocalStorage('demo-memo', '')
// オブジェクトもそのまま保存できる(JSONに変換される)
const settings = useLocalStorage('settings', { pageSize: 20, showDone: true })
// 保存先を sessionStorage にする
const draft = useStorage('draft', '', sessionStorage)
</script>

<template>
  <textarea id="memo" v-model="memo"></textarea>
  <label><input type="checkbox" v-model="settings.showDone" /> 完了も表示</label>
</template>

Playwrightでの実行結果(入力 → localStorageを確認 → 再読み込み):

localStorage: 備品の発注を確認する
再読み込み後のtextarea: 備品の発注を確認する

同じキーを使う別タブの変更も反映されます(storage イベントを監視しているため)。これは自作の数行版にはない機能です。

Sensors:メニューの外側クリックで閉じる(onClickOutside)

onClickOutside(要素, 処理) で、要素の外側がクリックされたときだけ処理が走ります。 ドロップダウンやモーダルでよく使います。

<script setup>
import { ref, useTemplateRef } from 'vue'
import { onClickOutside } from '@vueuse/core'

const open = ref(false)
const menu = useTemplateRef('menu')
onClickOutside(menu, () => { open.value = false })
</script>

<template>
  <div ref="menu">
    <button id="menu-btn" @click="open = !open">メニュー</button>
    <ul v-if="open" id="menu-list"><li>設定</li><li>ログアウト</li></ul>
  </div>
  <p id="outside">ここは外側です</p>
</template>

実行結果(ボタン → メニュー内をクリック → 外側をクリック):

メニュー表示: true
内側クリック後: true
外側クリック後: false

判定対象は ref="menu" を付けた要素の中かどうかです。ボタンをメニューの外に置くと、ボタンを押した瞬間に「外側クリック」と判定されて開閉がちらつくことがあります。ボタンも同じ要素の中に入れるか、ignore オプションで除外します。

Browser:ダークモードを切り替える(useDark / useToggle)

useDark は <html> に dark クラスを付け外しし、選んだ状態をlocalStorageに保存します。 初回はOSの設定(prefers-color-scheme)に従います。

<script setup>
import { useDark, useToggle } from '@vueuse/core'

const isDark = useDark()
const toggleDark = useToggle(isDark)
</script>

<template>
  <button id="dark" @click="toggleDark()">{{ isDark ? 'ライト' : 'ダーク' }}にする</button>
</template>

<style>
html.dark { background: #1e1e1e; color: #eee; }
</style>

実行結果:

html class(前): null
html class(後): dark / 保存値: dark
再読み込み後: dark / ボタン: ライトにする

保存キーは vueuse-color-scheme でした。Tailwind CSSの dark: を「classで切り替える」設定にしている場合、そのまま連携できます。

Utilities:検索の入力を間引く(useDebounceFn / refDebounced / watchDebounced)

入力のたびにAPIを呼ぶと回数が増えるため、「入力が止まって300ms後に1回だけ」実行します。

<script setup>
import { ref } from 'vue'
import { useDebounceFn, refDebounced, watchDebounced } from '@vueuse/core'

const keyword = ref('')
const searchCount = ref(0)

// ① 関数を間引く
const search = useDebounceFn(() => { searchCount.value++ }, 300)

// ② 値を間引いたrefを作る(computedやテンプレートで使う)
const debouncedKeyword = refDebounced(keyword, 300)

// ③ watchを間引く(maxWaitで最大待ち時間も指定できる)
watchDebounced(keyword, (v) => console.log('検索:', v), { debounce: 300, maxWait: 1000 })
</script>

<template>
  <input id="kw" v-model="keyword" @input="search" />
  <p id="count">{{ searchCount }}</p>
</template>

実行結果(50ms間隔で notebook の8文字を入力し、500ms待つ):

8文字入力後の検索回数: 1

useThrottleFn はv15で「最後の1回も実行する(trailing: true)」が既定になりました。 500msのスロットルで5回連打したところ、直後は1回、0.8秒後には2回になりました(最初の1回+最後の1回)。

Elements:要素の大きさと表示状態(useElementSize / useIntersectionObserver)

遅延読み込みなど「一度見えたら処理」は useIntersectionObserver、表示の出し分けだけなら useElementVisibility が手軽です。

<script setup>
import { ref, useTemplateRef } from 'vue'
import { useElementSize, useIntersectionObserver, useElementVisibility } from '@vueuse/core'

const box = useTemplateRef('box')
const { width, height } = useElementSize(box)

const target = useTemplateRef('target')
const seen = ref(false)
// 一度でも画面に入ったら true にして監視をやめる
const { stop } = useIntersectionObserver(target, ([entry]) => {
  if (entry.isIntersecting) { seen.value = true; stop() }
})
const visible = useElementVisibility(target)  // 今見えているか
</script>

<template>
  <div ref="box">{{ Math.round(width) }} × {{ Math.round(height) }}</div>
  <div ref="target">{{ seen ? '表示されました' : '' }} / 見えている: {{ visible }}</div>
</template>

Browser:コピー・タイトル・画面幅(useClipboard / useTitle / useMediaQuery / useBreakpoints)

<script setup>
import { computed } from 'vue'
import { useClipboard, useTitle, useMediaQuery, useBreakpoints, breakpointsTailwind } from '@vueuse/core'

const orderNo = 'A-20260928-001'
const { copy, copied, isSupported } = useClipboard({ copiedDuring: 1500 })

const count = 3
useTitle(computed(() => `未読 ${count} 件 | タスク管理`))

const isWide = useMediaQuery('(min-width: 768px)')
const bp = useBreakpoints(breakpointsTailwind)
const isMdUp = bp.greaterOrEqual('md')
</script>

<template>
  <button v-if="isSupported" @click="copy(orderNo)">{{ copied ? 'コピーしました' : '注文番号をコピー' }}</button>
  <p>{{ isWide ? 'PC表示' : 'スマホ表示' }} / md以上: {{ isMdUp }}</p>
</template>

useClipboard はHTTPSまたはlocalhostでのみ動きます(ブラウザのClipboard APIの制約)。isSupported で表示を出し分けると安全です。

Sensors:スクロール・キー操作・無限スクロール

<script setup>
import { ref, useTemplateRef } from 'vue'
import { useScroll, onKeyStroke, useInfiniteScroll } from '@vueuse/core'

const list = useTemplateRef('list')
const { y, arrivedState } = useScroll(list)

const items = ref(Array.from({ length: 20 }, (_, i) => `記事 ${i + 1}`))
const hasMore = ref(true)
useInfiniteScroll(list, async () => {
  const next = items.value.length
  items.value.push(...Array.from({ length: 10 }, (_, i) => `記事 ${next + i + 1}`))
  if (items.value.length >= 100) hasMore.value = false
}, { distance: 10, canLoadMore: () => hasMore.value })

const open = ref(true)
onKeyStroke('Escape', () => { open.value = false })
</script>

<template>
  <p>位置: {{ Math.round(y) }} / 下端: {{ arrivedState.bottom }}</p>
  <ul ref="list" style="height: 300px; overflow-y: auto">
    <li v-for="item in items" :key="item">{{ item }}</li>
  </ul>
</template>

canLoadMore を返さないと、最後まで読み込んだあとも呼ばれ続けます。 件数やAPIの「次ページなし」で止めるようにします。

Network:APIを呼ぶ(useFetch)

<script setup>
import { ref, computed } from 'vue'
import { useFetch } from '@vueuse/core'

const page = ref(1)
const url = computed(() => `/api/articles?page=${page.value}`)
// refetch: true で url が変わるたびに再取得
const { data, error, isFetching } = useFetch(url, { refetch: true }).get().json()
</script>

<template>
  <p v-if="isFetching">読み込み中…</p>
  <p v-else-if="error">取得に失敗しました</p>
  <ul v-else><li v-for="a in data" :key="a.id">{{ a.title }}</li></ul>
  <button @click="page++">次のページ</button>
</template>

共通のベースURLや認証ヘッダーを付けたいときは createFetch({ baseUrl, options: { beforeFetch } }) で専用の useFetch を作ります。 Nuxtでは同名の useFetch がNuxt側にあるため、後述のとおりVueUse版は自動importされません。

Time・State:時刻・履歴・共有

<script setup>
import { ref } from 'vue'
import { useDateFormat, useTimeAgoIntl, useRefHistory } from '@vueuse/core'

const created = new Date(2026, 8, 28, 9, 5)
const dateLabel = useDateFormat(created, 'YYYY/MM/DD(ddd) HH:mm', { locales: 'ja-JP' })
const ago = useTimeAgoIntl(created, { locale: 'ja' })

const text = ref('')
const { undo, redo, canUndo, canRedo } = useRefHistory(text, { capacity: 20 })
</script>

<template>
  <p>{{ dateLabel }}({{ ago }})</p>
  <input v-model="text" />
  <button :disabled="!canUndo" @click="undo()">元に戻す</button>
  <button :disabled="!canRedo" @click="redo()">やり直す</button>
</template>

実行結果(日付の書式はChromium、相対時間は「5分前の日時」をNode.jsで渡した結果):

日付: 2026/09/28(月) 09:05
useTimeAgo: 5 minutes ago
useTimeAgoIntl: 5 分前

useTimeAgo の既定は英語表記です。日本語で表示したい場合は、ブラウザの Intl.RelativeTimeFormat を使う useTimeAgoIntl が手軽でした。

関数を1つ使うと何バイト増える?(Viteで実測)

VueUseは使った関数だけがバンドルに入ります(tree-shaking)。 「200以上の関数が入ったライブラリを入れると重くなるのでは」と気になる方のために、実際に測りました。

測り方

  1. ref(0) を表示するだけの最小のVueアプリを「基準」としてビルド
  2. 基準に関数を1つだけ追加したアプリを関数ごとに作ってビルド
  3. 出力されたJSを gzip -9 相当で圧縮したサイズを比べる

(Vite 8.3.1 の本番ビルド、@vueuse/core 15.0.0。基準のJSはgzipで23,850バイトで、ほぼVue本体の大きさです)

実測結果

追加した関数 増えたサイズ(gzip)
useToggle +134 B
useEventListener +257 B
useIntervalFn +283 B
useThrottleFn +289 B
useNow +420 B
useDebounceFn +443 B
useIntersectionObserver +550 B
useDateFormat +716 B
useMouse +824 B
useMediaQuery +860 B
useElementSize +872 B
useTitle +995 B
onClickOutside +1,078 B
useClipboard +1,371 B
useBreakpoints +1,429 B
useStorage +2,022 B
useLocalStorage +2,041 B
useScroll +2,075 B
useFetch +2,434 B
useInfiniteScroll +2,751 B
useDark +3,162 B
上の22関数をまとめて使う +11,264 B
import * as VueUse で全部読み込む +49,335 B

1関数あたり数百バイト〜3KB程度で、22関数をまとめて使っても約11KBでした。 個別の増加分を足すと約25KBになりますが、まとめると内部の共通処理(イベント登録やストレージ処理など)が共有されるため半分以下に収まっています。

一方、import * as VueUse from '@vueuse/core' のように名前空間ごと読み込んで使うと、約49KB増えました。 使う関数を名前付きで import { useMouse } from '@vueuse/core' と書けば、この差は出ません。

自作した場合と比べると

同じ目的の処理を最小限のコードで自作し、同じ方法で測りました。

処理 VueUse 自作(最小限) VueUseに含まれている主な処理
localStorageに保存 +2,041 B +34 B SSRで落ちない、型に合わせた変換、別タブとの同期、エラー処理
外側クリック検知 +1,078 B +99 B iframe・ドラッグ操作への配慮、除外要素(ignore)、解除関数
デバウンス +443 B ほぼ0 B maxWait、Promiseを返す、引数の受け渡し

差の分だけ「端のケース」への対応が入っていると考えると判断しやすくなります。 たとえば自作のlocalStorage版は、次の章のとおりSSRで localStorage is not defined になります。

気をつけたい点:戻り値を使わない useNow はビルドで消える

検証中、const now = useNow({...}) の now をテンプレートで使っていないと、本番ビルドで useNow の呼び出しごと消えて、コールバックが1回も動きませんでした(更新回数0回)。テンプレートで now を表示すると3回に戻りました。

VueUseのソースを見ると、useNow などの一部の関数には /* @__NO_SIDE_EFFECTS__ */(戻り値を使わなければ削除してよい、という目印) が付いています。「戻り値を使わず、副作用だけが目的」なら useIntervalFn のように処理を直接実行する関数を使うと、意図どおりに動きます。

SSR・Nuxtで使うときの注意点

SSRでは window がないので、初期値が返る

VueUseの関数は、サーバー側(window がない環境)で呼ばれてもエラーにならず、初期値を返すように作られています。 Vueの renderToString で確かめた結果です。

import { createSSRApp, h, ref } from 'vue'
import { renderToString } from 'vue/server-renderer'
import { useLocalStorage, useDark, useWindowSize, useMediaQuery } from '@vueuse/core'

const WithVueUse = { setup() {
  const memo = useLocalStorage('memo', '(未入力)')
  const isDark = useDark()
  const { width } = useWindowSize()
  const wide = useMediaQuery('(min-width: 768px)')
  return () => h('p', `memo=${memo.value} dark=${isDark.value} width=${width.value} wide=${wide.value}`)
} }
const Handmade = { setup() {
  const memo = ref(localStorage.getItem('memo') ?? '')
  return () => h('p', memo.value)
} }

console.log('VueUse:', await renderToString(createSSRApp(WithVueUse)))
try { await renderToString(createSSRApp(Handmade)) } catch (e) { console.log('自作:', e.constructor.name + ': ' + e.message) }
VueUse: <p>memo=(未入力) dark=false width=Infinity wide=false</p>
[Vue warn]: Unhandled error during execution of setup function
自作: ReferenceError: localStorage is not defined

サーバー側では useWindowSize の幅が Infinity、useMediaQuery は false になりました。 この値でサーバーが描画し、ブラウザ側で実際の値に変わるため、画面幅で見た目を大きく変える部分は、描画の食い違い(hydration mismatch)やちらつきが起きやすくなります。 次のように対策します。

起きること 対策
画面幅で表示を切り替えると、サーバーとブラウザで内容が違う 見た目の切り替えはCSSのメディアクエリで行う/<ClientOnly> で囲む
useWindowSize の初期幅が Infinity useWindowSize({ initialWidth: 1024 }) のように初期値を渡す
ダークモードが読み込み直後に一瞬ライトになる Nuxtでは ssrHandlers を有効にする(下記)、または @nuxtjs/color-mode を使う
localStorageの値がサーバーでは読めない 初期値で描画される前提で作る/Cookieに保存する

Nuxtでは @vueuse/nuxt を入れる

Nuxtでは @vueuse/nuxt モジュールを入れると、VueUseの関数が自動importされ、import を書かずに使えます。

npx nuxt@latest module add vueuse

手動で入れる場合は npm i -D @vueuse/nuxt @vueuse/core を実行し、設定ファイルに追加します。

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vueuse/nuxt'],
  vueuse: {
    ssrHandlers: true,  // localStorage系の保存先をCookieにし、html属性をuseHeadで出力
  },
})

@vueuse/nuxt 15.0.0 のソースで確認した動きは次のとおりです(Nuxtアプリ上での実行はしていません)。

項目 内容
自動importされない関数 useFetch・useCookie・useHead・useStorage・useImage・toRef・toRefs・toValue(Nuxt・Vueの同名関数を優先)
@nuxtjs/color-mode があるとき useColorMode も自動importの対象外になる
ssrHandlers: true ストレージの保存先をCookie(useCookie)にし、useDark などによる <html> の属性をサーバー側で useHead で出力
対応Nuxt peerDependencies は nuxt: ^3.0.0 || ^4.0.0-0 || ^5.0.0-0

useFetch はNuxtの同名関数(サーバーでの取得と結果の受け渡しに対応)が使われます。 VueUse版を使いたいときは import { useFetch } from '@vueuse/core' と明示します。

よくあるつまずきと直し方

症状 原因 直し方
onClickOutside でボタンを押すと即閉じる ボタンが判定対象の要素の外にある ボタンを同じ要素に入れる/ignore で除外
バンドルが大きい import * や名前空間で使っている 名前付きimportにする
SSRで表示がずれる サーバーでは初期値で描画される CSSで切り替える/<ClientOnly>/初期値を渡す
コールバックが動かない 戻り値を使わない関数がビルドで削除された 戻り値を使う/処理を直接実行する関数を使う

よくある質問

Q. VueUseは本番のプロジェクトで使っても大丈夫ですか? A. 使った関数だけがバンドルに入り、今回の実測では1関数あたり数百バイト〜3KB程度でした。@vueuse/core は継続的にリリースされており、今回の最新版は2026年9月公開のv15.0.0です。導入時はメジャーバージョンを固定し、更新時にリリースノートの破壊的変更を確認するのがおすすめです。

Q. Vue 2のプロジェクトでもVueUseは使えますか? A. VueUse 12以降はVue 3専用です。Vue 2.7のプロジェクトでは、公式ガイドの案内どおりVueUse 11系を使うとComposition APIと組み合わせて利用できます。

Q. VueUseの関数と自作のcomposable、どちらを使えばよいですか? A. イベント登録の解除やSSR対応など「端のケース」が多い処理はVueUseを、業務ロジック(注文の合計計算など)は自作のcomposableにするのが基本です。VueUseの関数を組み合わせて自作composableを作る書き方もよく使われます。

まとめ

  • VueUseはVue 3用の便利関数集。import { 関数名 } from '@vueuse/core' で使いたいものだけ読み込む
  • よく使うのは State(保存)・Elements(要素)・Browser(ブラウザ機能)・Sensors(操作) の4カテゴリ
  • v15(2026年9月) は templateRef 削除、Node 22以上、useNow などの更新間隔は scheduler で指定、useThrottleFn は trailingが既定でtrue
  • 実測で1関数あたり+134B〜+3.2KB(gzip)、22関数で+11KB。名前空間ごとの読み込みは+49KBになる
  • 自作より大きい分、SSRで落ちない・後片付け・タブ間同期などが入っている
  • SSRでは初期値で描画されるので、画面幅やダークモードの扱いに注意。Nuxtでは @vueuse/nuxt を使う
  • Vue 2のプロジェクトは VueUse 11系 で、今の環境のまま恩恵を受けられる

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「VueUseの使い方|よく使う30関数の早見表とサイズ実測【v15】」

株式会社RJCでは、VueUseのような便利なライブラリも「どこまで任せて、どこを自分たちで書くか」を実測しながら判断し、プロジェクトの中で共有しています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?