本文へ移動
cccskills
無料GitHub で公開

web-utilities-vueuse

VueUse composable utility collection for Vue 3 - browser, sensor, network, state, animation, and component utilities

インストール方法を見る

含まれるファイル(8)

  • SKILL.md11.1 KB
  • examples/component.md5.6 KB
  • examples/core.md5.3 KB
  • examples/network.md5.0 KB
  • examples/sensors.md4.6 KB
  • examples/state.md4.2 KB
  • metadata.yaml498 B
  • reference.md7.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

VueUse Composable Patterns

Quick Guide: VueUse wraps browser APIs, sensors, network transports and small state utilities as composables that return refs and clean themselves up on scope disposal. Import each function by name from @vueuse/core — the library is large and entirely tree-shakeable. Two things decide whether a call works: it must run synchronously during setup, because teardown binds to the effect scope that is current at call time; and browser-API composables behave differently on a server, some returning a safe default and some needing client-only rendering.

Detailed Resources:


Which path applies

Server rendering is the branch, because it changes which composables are usable at all.

  • Client-rendered only — every composable is available; call it and read the ref.
  • Server-rendered — storage, media-query and preference composables return their declared default on the server and hydrate on the client. Sensor and transport composables (useMouse, useScroll, useIntersectionObserver, useWebSocket, useClipboard) need a DOM and belong inside a client-only boundary. The table in reference.md says which is which.
  • The composable wraps an API not every browser has — read its isSupported ref and render a fallback, rather than assuming the call worked.

<critical_requirements>

Before writing VueUse code

Call composables synchronously during setup. Teardown registers against the effect scope that is current when the composable runs, so a call inside an await, a setTimeout or an event handler has no scope to attach to and its listeners are never removed.

Import each composable by name from @vueuse/core. A namespace import pulls the whole library past the bundler's tree-shaker, and the library is several hundred functions.

Read isSupported where the composable wraps an optional browser API — clipboard, share, geolocation, battery, wake lock. It exists because the API can be absent or permission-gated, and the fallback path is what the user sees when it is.

Decide the server behaviour before the composable ships. Each one either returns a declared default on the server or needs a client-only boundary; guessing produces a hydration mismatch, which reports as a rendering bug far from its cause.

</critical_requirements>


Auto-detection: VueUse, vueuse, @vueuse/core, @vueuse/integrations, useLocalStorage, useSessionStorage, useClipboard, useFetch, createFetch, useMouse, useMouseInElement, useScroll, useIntersectionObserver, useResizeObserver, useElementVisibility, useElementSize, useMediaQuery, usePreferredDark, useDark, useToggle, useCounter, useCycleList, useWebSocket, useEventSource, useEventListener, useTransition, useRafFn, createGlobalState, useRefHistory, useManualRefHistory, syncRef, useVModel, useVirtualList, onClickOutside, onKeyStroke, useDebounceFn, watchDebounced

Applies to:

  • Browser APIs as reactive refs — storage, clipboard, media queries, preferences
  • Sensor readings — pointer position, scroll, intersection, element size and visibility
  • Reactive HTTP, WebSocket and server-sent-event transports
  • Small shared state, undo history, and ref synchronisation
  • Component helpers — two-way binding, virtual lists, outside clicks, key strokes, value animation

Handled elsewhere:

  • Server-state caching, invalidation and optimistic updates — a distinct problem that a reactive request wrapper does not solve
  • Application state architecture — actions, modules and devtools belong to whatever owns the store
  • The reactivity primitives themselves — ref, computed, watch and effect scopes are the framework's, and these composables are built on top of them
  • Routing, forms and validation — none of these composables model any of it

<philosophy>

Each composable owns one concern and its own teardown. That is the whole contract: it returns refs, it registers whatever listener or observer it needs, and it disposes of them when the surrounding effect scope ends. Nothing is registered globally and nothing needs a plugin.

The consequence is that the call site owns the lifetime. Two components calling useMouse() get two independent listeners, both cleaned up separately — which is why sharing one instance is an explicit act (createGlobalState, or a composable of your own) rather than something the library does for you.

</philosophy>
<patterns>

Core patterns

Pattern 1: Reactive storage

import { useLocalStorage } from "@vueuse/core";

const settings = useLocalStorage("app-settings", DEFAULTS, {
  mergeDefaults: true, // stored data gains fields added to DEFAULTS since it was written
});

settings.value.theme = "dark"; // persists, and other tabs see it
settings.value = null; // removes the key entirely — it does not store null

Serialisation, cross-tab sync via the storage event, and a server-side default all come with it. Full code: examples/core.md


Pattern 2: Listeners that remove themselves

import { useEventListener } from "@vueuse/core";
import { useTemplateRef } from "vue";

const dropZone = useTemplateRef("drop-zone");

useEventListener(window, "resize", onResize);
useEventListener(dropZone, "drop", onDrop); // waits for the ref to be populated

Passing a ref rather than an element is the point: the composable attaches once the element exists and re-attaches if it changes, so there is no mount-order problem to solve by hand.

Full code: examples/core.md


Pattern 3: Media queries and colour scheme

import {
  useMediaQuery,
  usePreferredDark,
  useDark,
  useToggle,
} from "@vueuse/core";

const isMobile = useMediaQuery("(max-width: 768px)");
const prefersDark = usePreferredDark(); // reads the OS setting
const isDark = useDark(); // reads it, persists an override, toggles a class
const toggleDark = useToggle(isDark);

usePreferredDark observes; useDark also writes — it persists the choice and toggles a class on the root element, so the class name it uses has to match what the stylesheet expects.

Full code: examples/core.md


Pattern 4: Sensors

import { useScroll, useIntersectionObserver } from "@vueuse/core";

const { y, directions, arrivedState } = useScroll(container);

useIntersectionObserver(
  sentinel,
  ([entry]) => {
    if (entry?.isIntersecting) loadMore();
  },
  { rootMargin: "200px" },
); // fire before it reaches the viewport

arrivedState and directions are the parts worth knowing — they replace the offset arithmetic that scroll handlers usually get wrong at the edges.

Full code: examples/sensors.md


Pattern 5: Reactive fetch

import { useFetch } from "@vueuse/core";

const url = computed(() => `/api/users/${userId.value}`);

// Re-runs whenever `url` changes, and aborts the previous request
const { data, isFetching, error, abort } = useFetch(url, {
  refetch: true,
}).json<User>();

// Manual: no request until execute() is called
const { execute } = useFetch("/api/users", { immediate: false })
  .post(body)
  .json();

The chained .json<T>() is what types data; without it you hold a Ref<string | null>.

Full code: examples/network.md


Pattern 6: Shared state without a store library

import { createGlobalState } from "@vueuse/core";

export const useGlobalCounter = createGlobalState(() => {
  const count = shallowRef(0);
  const double = computed(() => count.value * 2);
  const increment = () => count.value++;

  return { count, double, increment };
});

The factory runs once and every caller gets the same refs. Returning actions rather than the bare writable refs is what keeps the mutation points countable.

Full code: examples/state.md


Pattern 7: Two-way binding

import { useVModel } from "@vueuse/core";

const value = useVModel(props, "modelValue", emit);
const count = useVModel(props, "count", emit); // named v-model

value.value = next; // emits update:modelValue

One line where the get/set computed is five, and the event name is derived rather than typed out — which is where the typo used to live.

Full code: examples/component.md

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • A composable called inside await, setTimeout or an event handler binds to no effect scope: its listeners and observers are never disposed of, and the component leaks them on every mount.
  • A sensor or transport composable called during server rendering touches window or document and throws. Move it behind a client-only boundary.
  • Using a browser-API composable without checking isSupported fails on the browsers and contexts where the API is missing or permission-gated — clipboard write outside a user gesture is the usual first case.
  • A namespace import of @vueuse/core defeats tree-shaking and ships the whole library.

Surprising behaviour:

  • useLocalStorage(...).value = null deletes the key rather than storing null. Store an explicit empty value where the key must survive.
  • createGlobalState is a singleton for the module's lifetime — it survives every component unmounting and is cleared only by a reload, which makes it a poor fit for per-user state that must reset on sign-out.
  • useIntersectionObserver invokes its callback once on registration with the element's current state, so "became visible" needs comparing against the previous value rather than trusting the first call.
  • useFetch fires on mount by default; refetch: true adds re-firing on URL change without removing the initial one. immediate: false is what makes it fully manual.
  • useWebSocket reconnects by default, so a server rejecting the connection produces a retry loop until autoReconnect: false or a bounded retries says otherwise.
  • useRefHistory snapshots every change, which on a text input is one entry per keystroke. Give it a capacity, or use useManualRefHistory and commit at save points.
  • shallowRef avoids deep-reactivity cost on large objects, but a composable that persists or watches nested changes — useLocalStorage among them — needs the deep tracking to see them at all. Choose per composable rather than as a blanket rule.

</red_flags>

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

agents-inc のスキルをすべて見る

このスキルの問題を報告する