From ravn-ai-toolkit
Provides React 19 patterns for components, hooks, Server Components, data fetching, Suspense boundaries, and render optimization via memoization. Use when writing or refactoring React code.
npx claudepluginhub ravnhq/ai-toolkitThis skill is limited to using the following tools:
React patterns evolve with each major version. React 19 introduced the `use()` hook for promise handling and formalized Server Component boundaries with clearer client/server semantics. Common pitfalls include:
rules/_sections.mdrules/component-no-mutation-callbacks.mdrules/component-semantic-elements.mdrules/component-use-key-for-reset.mdrules/effect-cleanup.mdrules/effect-when-not-needed.mdrules/hooks-rules.mdrules/hooks-use-for-promises.mdrules/perf-no-premature-memo.mdrules/perf-stable-keys.mdrules/server-client-boundaries.mdApplies opinionated conventions for React 18+/19 components: hooks patterns, Server Components, Suspense boundaries, state management, performance memoization, use() hook, form actions. Use for building performant apps.
Provides decision trees for React hooks selection, component patterns, state management with Zustand/React Query, Server Components, and performance optimization.
Builds React 18+ components, custom hooks, and state management; debugs rendering issues, migrates class components, optimizes performance, and implements Server Components, Suspense, useActionState in Next.js App Router or CRA.
Share bugs, ideas, or general feedback.
React patterns evolve with each major version. React 19 introduced the use() hook for promise handling and formalized Server Component boundaries with clearer client/server semantics. Common pitfalls include:
React 19 improves these patterns: use() hook for consuming promises, Server Components for data fetching without extra requests, and useTransition() for non-blocking updates.
use() hook calls with Suspense boundaries for loading fallbackSee rules index for detailed patterns.
User: "Refactor this React component to reduce re-renders and clarify hook usage."
Expected behavior: Use tech-react guidance, follow its workflow, and return actionable output.
User: "I'm fetching data on the client with useEffect. How should I refactor this with Server Components?"
Expected behavior: Move data fetch to Server Component, pass promise to Client Component via use() hook, wrap with Suspense boundary.
User: "Write a Bash script to package release artifacts."
Expected behavior: Do not prioritize tech-react; choose a more relevant skill or proceed without it.
enabled option in data hooks to skip executionuse() suspendsuse()<Suspense> is a parent of the component, not a siblingkey={index} to key={item.id} with unique property from dataIncorrect:
function UserProfile({ userId }: { userId: string | null }) {
if (!userId) {
return <div>Select a user</div>;
}
// Hook called conditionally - React can't track it!
const [profile, setProfile] = useState(null);
return <div>{profile?.name}</div>;
}
Correct:
function UserProfile({ userId }: { userId: string | null }) {
const [profile, setProfile] = useState(null);
// Early return AFTER hooks
if (!userId) {
return <div>Select a user</div>;
}
return <div>{profile?.name}</div>;
}
Incorrect:
function Comments({ id }: { id: string }) {
const [comments, setComments] = useState([]);
useEffect(() => {
fetchComments(id).then(setComments);
}, [id]);
return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>;
}
Correct:
function Comments({ commentsPromise }: { commentsPromise: Promise<Comment[]> }) {
const comments = use(commentsPromise);
return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>;
}
function CommentsSection({ id }: { id: string }) {
return (
<Suspense fallback={<div>Loading comments...</div>}>
<Comments commentsPromise={fetchComments(id)} />
</Suspense>
);
}
Incorrect:
// BAD: Server Component with useState
async function NotesPage() {
const [selectedNote, setSelectedNote] = useState(null); // ERROR: Can't use state
const notes = await db.notes.getAll();
return (
<div>
{notes.map(note => (
<button onClick={() => setSelectedNote(note)}>
{note.title}
</button>
))}
</div>
);
}
Correct:
// Server Component - fetch data
async function NotesPage() {
const notes = await db.notes.getAll();
return (
<div>
<NotesList notes={notes} />
</div>
);
}
// Client Component - handle interaction
"use client";
function NotesList({ notes }: { notes: Note[] }) {
const [selectedNote, setSelectedNote] = useState<Note | null>(null);
return (
<div>
{notes.map(note => (
<button
key={note.id}
onClick={() => setSelectedNote(note)}
>
{note.title}
</button>
))}
</div>
);
}