askill
react-patterns

react-patternsSafety --Repository

React component patterns, hooks, server components, and composition. Use when building React components or deciding between patterns.

0 stars
1.2k downloads
Updated 1/22/2026

Package Files

Loading files...
SKILL.md

React Patterns

Overview

Decision guide for React patterns focusing on component architecture, hooks, and the server/client component model.

Server vs Client Components

Decision Matrix

NeedComponent TypeDirective
Data fetchingServer(none)
Direct DB accessServer(none)
Static contentServer(none)
Event handlersClient'use client'
useState/useEffectClient'use client'
Browser APIsClient'use client'

Pattern: Composition for Interactivity

// Server component (default) - does data fetching
async function UserProfile({ id }: { id: string }) {
  const user = await db.user.findUnique({ where: { id } });
  return (
    <div>
      <h1>{user.name}</h1>
      <FollowButton userId={id} /> {/* Client component island */}
    </div>
  );
}

// Client component - handles interactivity
'use client';
function FollowButton({ userId }: { userId: string }) {
  const [following, setFollowing] = useState(false);
  return <button onClick={() => setFollowing(!following)}>Follow</button>;
}

Component Composition

Compound Components (for related UI)

function Tabs({ children }: { children: React.ReactNode }) {
  const [active, setActive] = useState(0);
  return (
    <TabsContext.Provider value={{ active, setActive }}>
      {children}
    </TabsContext.Provider>
  );
}

Tabs.List = TabsList;
Tabs.Panel = TabsPanel;

// Usage: <Tabs><Tabs.List>...</Tabs.List></Tabs>

Render Props (for behavior sharing)

function DataFetcher<T>({
  url,
  children
}: {
  url: string;
  children: (data: T | null, loading: boolean) => ReactNode
}) {
  const { data, loading } = useFetch<T>(url);
  return children(data, loading);
}

Hook Patterns

Custom Hook Structure

function useAsync<T>(asyncFn: () => Promise<T>) {
  const [state, setState] = useState<{
    data: T | null;
    error: Error | null;
    loading: boolean;
  }>({ data: null, error: null, loading: true });

  useEffect(() => {
    asyncFn()
      .then(data => setState({ data, error: null, loading: false }))
      .catch(error => setState({ data: null, error, loading: false }));
  }, [asyncFn]);

  return state;
}

useEffect Dependencies

// GOOD: Stable reference with useCallback
const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);

// GOOD: Object dependencies via useMemo
const options = useMemo(() => ({ page, limit }), [page, limit]);

Anti-Patterns

Anti-PatternProblemSolution
Props drilling 3+ levelsHard to maintainContext or composition
useEffect for derived stateExtra rendersuseMemo or compute in render
Inline object/array propsBreaks memoizationuseMemo or extract constant
Giant components (300+ lines)Hard to test/readExtract sub-components
useEffect for data syncRace conditionsUse query library (TanStack)
// BAD: Derived state in useEffect
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(`${first} ${last}`);
}, [first, last]);

// GOOD: Compute during render
const fullName = `${first} ${last}`;

Performance Decisions

SituationTool
Expensive calculationuseMemo
Callback passed to childuseCallback
Prevent child re-renderReact.memo
Non-blocking updateuseTransition
Show stale during loaduseDeferredValue

Rule: Profile first. Don't prematurely optimize.

Form Patterns

// Prefer controlled with form library
const form = useForm<FormData>({
  resolver: zodResolver(schema),
  defaultValues: { name: '' },
});

// Uncontrolled for simple cases
const inputRef = useRef<HTMLInputElement>(null);
const handleSubmit = () => console.log(inputRef.current?.value);

Red Flags

  • 'use client' at top of every file (server components are default)
  • useEffect with empty deps that should run once on mount
  • State that could be URL params (use useSearchParams)
  • Fetching in useEffect (use server components or TanStack Query)
  • Context for frequently changing values (causes re-renders)

Quick Reference

// ForwardRef pattern
const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => (
  <input ref={ref} {...props} />
));

// Error boundary (class required)
class ErrorBoundary extends Component<Props, State> {
  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }
}

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

AI review pending.

Metadata

Licenseunknown
Version-
Updated1/22/2026
Publishererikpr1994

Tags

testing