Core React 19 patterns for DSAI projects including hooks, Suspense, lazy loading, component structure with forwardRef, TypeScript best practices, and performance optimization. Use when working with React components, hooks, lazy loading, Suspense boundaries, or React-specific TypeScript patterns.
From hugin-v0npx claudepluginhub michelve/hugin-marketplace --plugin hugin-v0This skill uses the workspace's default tool permissions.
examples/lazy-loading.mdreference/common-mistakes.mdreference/hooks-patterns.mdreference/performance.mdreference/typescript-patterns.mdresources/component-patterns.mdresources/hooks-patterns.mdresources/performance.mdresources/typescript-patterns.mdGuides browser automation with Playwright, Puppeteer, Selenium for e2e testing and scraping. Teaches reliable selectors, auto-waits, isolation to fix flaky tests.
Provides checklists to review code for functionality, quality, security, performance, tests, and maintainability. Use for PRs, audits, team standards, and developer training.
Enforces A/B test setup with gates for hypothesis locking, metrics definition, sample size calculation, assumptions checks, and execution readiness before implementation.
Essential React 19 patterns for building modern applications with hooks, Suspense, lazy loading, and TypeScript.
Note: DSAI Component Convention (React 19):
forwardRef is REQUIRED for all DSAI components — use memo(forwardRef(function Name(props, ref))) patterndisplayName property*.types.ts filespropTypes removed (use TypeScript interfaces)React.FC type discouraged — use direct function components with typed propsimport { forwardRef, memo, useState, useCallback } from 'react';
import { cn } from '@/lib/utils';
import type { UserProfileProps } from './UserProfile.types';
// Props defined in UserProfile.types.ts:
// interface UserProfileProps {
// userId: string;
// onUpdate?: (data: UserData) => void;
// className?: string;
// }
export const UserProfile = memo(
forwardRef<HTMLDivElement, UserProfileProps>(
function UserProfile({ userId, onUpdate, className }, ref) {
const [data, setData] = useState<UserData | null>(null);
const handleUpdate = useCallback((newData: UserData) => {
setData(newData);
onUpdate?.(newData);
}, [onUpdate]);
return (
<div ref={ref} className={cn('user-profile', className)}>
{/* Component content */}
</div>
);
}
)
);
UserProfile.displayName = 'UserProfile';
Creating a React component? Follow this:
memo(forwardRef(function Name(props, ref))) patterndisplayName on every component*.types.ts filecn() for class name composition (Bootstrap classes, not Tailwind)useCallback for event handlers passed to childrenuseMemo for expensive computationslazy(() => import())<Suspense> with fallback@/components/ui/ for DSAI componentsSee hooks-patterns.md for useState, useCallback, useMemo, and useEffect patterns with TypeScript examples.
See lazy-loading.md for React.lazy, Suspense fallbacks, and feature-based code splitting examples.
// Wrap data-fetching components
<Suspense fallback={<Skeleton />}>
<UserProfile userId={id} />
</Suspense>
// Nested Suspense for granular loading
<Suspense fallback={<PageLoader />}>
<Header />
<Suspense fallback={<ContentSkeleton />}>
<MainContent />
</Suspense>
<Footer />
</Suspense>
import { ErrorBoundary } from 'react-error-boundary';
<ErrorBoundary fallback={<ErrorFallback />}>
<Suspense fallback={<Loading />}>
<DataComponent />
</Suspense>
</ErrorBoundary>
See typescript-patterns.md for component props, hooks typing, and custom hook return types.
See performance.md for React.memo usage, custom comparison functions, and avoiding re-renders.
// Ternary operator
{isLoading ? <Spinner /> : <Content />}
// Logical AND
{error && <ErrorMessage error={error} />}
// Nullish coalescing
{user ?? <GuestView />}
// Early return for loading states
function Component() {
const { data } = useSomeHook();
// ❌ Avoid early returns for loading - breaks hooks rules
// Use Suspense instead
return <div>{data.map(...)}</div>;
}
// Always use stable keys
{items.map(item => (
<ItemCard key={item.id} item={item} />
))}
// Never use index as key if list can reorder
// ❌ Bad
{items.map((item, index) => (
<ItemCard key={index} item={item} />
))}
src/client/
├── components/
│ ├── ui/ # DSAI components (installed via `dsai add`)
│ │ ├── button/
│ │ │ ├── Button.tsx
│ │ │ ├── Button.types.ts
│ │ │ ├── Button.fsm.ts
│ │ │ └── index.ts
│ │ ├── modal/
│ │ └── card/
│ └── features/ # App-specific feature components
│ ├── auth/
│ └── posts/
├── hooks/ # Shared hooks (DSAI + custom)
├── lib/
│ └── utils/ # Utilities (cn, validators, etc.)
└── types/ # Shared types
components/ui/button/
├── Button.tsx # Component with forwardRef + displayName
├── Button.types.ts # TypeScript prop interfaces
├── Button.fsm.ts # FSM reducer (interactive components)
├── Button.test.tsx # Unit tests (Jest 30 + RTL)
├── Button.a11y.test.tsx # Accessibility tests (jest-axe)
└── index.ts # Barrel exports
See common-mistakes.md for conditional hooks, missing dependencies, and state mutation anti-patterns.
For more detailed patterns, see: