Install
npx skills add https://github.com/pproenca/dot-skills --skill reactSKILL.md
ProductSearch — with skill
import { useState, useTransition, useMemo } from 'react'
interface Product {
id: number
name: string
}
// ~5,000 products generated once at module level so the reference is stable
// across renders (lazy initializer pattern from rule 5.4).
const ALL_PRODUCTS: Product[] = Array.from({ length: 5000 }, (_, i) => ({
id: i + 1,
name: `Product ${i + 1} — ${['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon'][i % 5]} ${String.fromCharCode(65 + (i % 26))}`,
}))
export function ProductSearch() {
// One state cell for the raw input value — updates at high priority.
const [query, setQuery] = useState('')
// useTransition (rule 1.5): marks the filtering work as low-priority and
// interruptible so keystrokes never block while the list re-renders.
const [isPending, startTransition] = useTransition()
// A second state cell carries the committed (transitioned) query that drives
// the expensive filter. The input reads `query` for immediate display;
// the list reads `committedQuery` at deferred priority.
const [committedQuery, setCommittedQuery] = useState('')
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const value = e.target.value
setQuery(value) // high priority — input stays responsive
startTransition(() => { // low priority — can be interrupted
setCommittedQuery(value)
})
}
// useMemo (rule 6.5): the filter over 5,000 items is measurably expensive;
// skip it when committedQuery hasn't changed. The derived list is computed
// in render (rule 5.1) — no useState + useEffect mirroring.
const filteredProducts = useMemo(
() =>
committedQuery.trim() === ''
? ALL_PRODUCTS
: ALL_PRODUCTS.filter(p =>
p.name.toLowerCase().includes(committedQuery.toLowerCase())
),
[committedQuery]
)
return (
<div>
<input
type="search"
value={query}
onChange={handleChange}
placeholder="Search products…"
aria-label="Search products"
/>
{isPending && <span aria-live="polite"> Filtering…</span>}
<p>{filteredProducts.length} result{filteredProducts.length !== 1 ? 's' : ''}</p>
<ul>
{filteredProducts.map(p => (
<li key={p.id}>{p.name}</li>
))}
</ul>
</div>
)
}
Approach
The component uses useTransition (skill rule 1.5 — CRITICAL) to split the
onChange handler into two priorities: setQuery updates the controlled input
immediately at high priority so keystrokes are never blocked, while
setCommittedQuery inside startTransition marks the expensive filter work as
interruptible low-priority work. The filtered list is derived in render with
useMemo rather than mirrored into a separate useState + useEffect (rule
5.1), eliminating the derived-state-drift bug class; useMemo is justified here
because filtering 5,000 items on every render is measurably expensive and the
committedQuery dep is a stable primitive string (rule 6.5).
Related skills
vercel-react-best-practicesvercel-labs751KReact and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.vercel-composition-patternsvercel-labs361KReact composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.vercel-react-view-transitionsvercel-labs135KGuide for implementing smooth, native-feeling animations using React's View Transition API (`<ViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions viewpick-ui-libraryemilkowalski124KPick the right library for a given frontend task from a curated, opinionated list — numbers, OTP inputs, charts, command menus, virtualization, drag and drop, toasts, state, styling, and more. Only runs when explicitly invoked; it does not trigger on its own.