Back to list
oakoss

react

by oakoss

Open-source SaaS starter kit with React, TanStack, and Better Auth

0🍴 0📅 Jan 26, 2026

SKILL.md


name: react description: React hooks + performance patterns. Use for useEffect, useMemo, useCallback, memo, rerender, derived state, performance, bundle, optimize, hooks, state, useTransition, Promise.all, waterfall, async

React Fundamentals

Core Philosophy

Effects are escape hatches. They synchronize React with external systems. If no external system is involved, you likely don't need one.

Performance optimization is targeted. Don't memoize everything. Profile first, optimize measurable bottlenecks.

useEffect Decision Tree

Do I need useEffect?

Is there an external system involved?
├── No → Don't use useEffect
│   ├── Derived state? → Calculate during render
│   ├── Event response? → Handle in event handler
│   └── Data fetching? → Use TanStack Query
└── Yes → Maybe use useEffect
    ├── Browser APIs (focus, scroll, localStorage)
    ├── Third-party widgets (maps, charts)
    ├── Network connections (WebSockets)
    └── Analytics/logging

Derived State (No Effect Needed)

// ❌ Bad - useEffect for derived state
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);

// ✅ Good - calculate during render
const fullName = `${firstName} ${lastName}`;

// ✅ With memoization (only if expensive)
const sortedItems = useMemo(
  () => items.toSorted((a, b) => a.name.localeCompare(b.name)),
  [items],
);

Event Handlers (No Effect Needed)

// ❌ Bad - effect chain for event response
useEffect(() => {
  if (submitted) {
    navigate('/success');
  }
}, [submitted]);

// ✅ Good - handle in event
const handleSubmit = async () => {
  await submitForm();
  navigate('/success');
};

Performance Patterns

useMemo - Expensive Calculations Only

// ❌ Bad - memoizing cheap operations
const doubled = useMemo(() => value * 2, [value]);

// ✅ Good - memoizing expensive operations
const sortedItems = useMemo(
  () => items.toSorted((a, b) => a.price - b.price),
  [items],
);

// ✅ Good - maintaining referential equality for deps
const filterFn = useMemo(() => (item) => item.active, []);

useCallback - For Memoized Children Only

// ❌ Bad - useCallback without memoized child
const handleClick = useCallback(() => doSomething(), []);
return <button onClick={handleClick}>Click</button>;

// ✅ Good - useCallback for memoized child
const handleClick = useCallback(() => doSomething(id), [id]);
return <MemoizedChild onClick={handleClick} />;

Avoiding Re-renders

// ❌ Bad - object literal creates new reference every render
<Child style={{ color: 'red' }} />;

// ✅ Good - stable reference
const style = useMemo(() => ({ color: 'red' }), []);
<Child style={style} />;

// ✅ Better - define outside component if static
const style = { color: 'red' };
function Parent() {
  return <Child style={style} />;
}

Async Patterns

Parallel Fetches

// ❌ Bad - sequential (waterfall)
const user = await getUser(id);
const posts = await getPosts(id);
const comments = await getComments(id);

// ✅ Good - parallel with Promise.all
const [user, posts, comments] = await Promise.all([
  getUser(id),
  getPosts(id),
  getComments(id),
]);

useTransition for Non-Urgent Updates

const [isPending, startTransition] = useTransition();

const handleSearch = (query: string) => {
  // Urgent: update input immediately
  setQuery(query);

  // Non-urgent: can be interrupted
  startTransition(() => {
    setFilteredResults(filterItems(query));
  });
};

Lazy State Initialization

// ❌ Bad - expensive function runs every render
const [items, setItems] = useState(parseExpensiveData(raw));

// ✅ Good - lazy initialization runs once
const [items, setItems] = useState(() => parseExpensiveData(raw));

Set/Map for O(1) Lookups

// ❌ Bad - O(n) on every render
const isSelected = (id: string) => selectedIds.includes(id);

// ✅ Good - O(1) lookups with Set
const selectedSet = useMemo(() => new Set(selectedIds), [selectedIds]);
const isSelected = (id: string) => selectedSet.has(id);

Common Mistakes

MistakeFix
Derived state in useEffectCalculate during render
Effect chains (A→B→C)Derive all values directly
useMemo for simple valuesOnly memoize expensive computations
useCallback everywhereOnly for memoized child components
Object literals as propsDefine outside component or useMemo
Manual data fetchingUse TanStack Query
Sequential awaitsUse Promise.all for parallel ops
Array.includes in loopsUse Set with useMemo for O(1)
useState(expensiveInit())Use useState(() => expensiveInit())

Delegation

  • Data fetching: For queries and caching, see tanstack-query skill
  • Form state: For form handling, see tanstack-form skill
  • URL state: For routing and params, see tanstack-router skill
  • Error handling: For error boundaries, see error-boundaries skill
  • Full-stack flows: For integrated patterns, see integration-patterns skill
  • Code review: After optimizing components, delegate to code-reviewer agent

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

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

+20
LICENSE

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

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

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

0/5
Issue管理

オープンIssueが50未満

+5
言語

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

+5
タグ

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

+5

Reviews

💬

Reviews coming soon