Back to list
erikpr1994

react-patterns

by erikpr1994

0🍴 0📅 Jan 22, 2026

SKILL.md


name: react-patterns description: "React component patterns, hooks, server components, and composition. Use when building React components or deciding between patterns."

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

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 };
  }
}

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon