スキル一覧に戻る
majcheradam

react-best-practices

by majcheradam

react-best-practicesは、ソフトウェア開発を効率化するスキルです。開発ワークフロー全体をサポートし、チームの生産性向上とコード品質の改善を実現します。

462🍴 34📅 2026年1月23日
GitHubで見るManusで実行

SKILL.md


name: react-best-practices description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

React Best Practices

Overview

Comprehensive performance optimization guide for React and Next.js applications, containing 40+ rules across 8 categories. Rules are prioritized by impact to guide automated refactoring and code generation.

When to Apply

Reference these guidelines when:

  • Writing new React components or Next.js pages
  • Implementing data fetching (client or server-side)
  • Reviewing code for performance issues
  • Refactoring existing React/Next.js code
  • Optimizing bundle size or load times

Priority-Ordered Guidelines

PriorityCategoryImpact
1Eliminating WaterfallsCRITICAL
2Bundle Size OptimizationCRITICAL
3Server-Side PerformanceHIGH
4Client-Side Data FetchingMEDIUM-HIGH
5Re-render OptimizationMEDIUM
6Rendering PerformanceMEDIUM
7JavaScript PerformanceLOW-MEDIUM
8Advanced PatternsLOW

Category 1: Eliminating Waterfalls (CRITICAL)

Rule: Defer await until needed

Bad:

async function Page() {
  const data = await fetchData(); // Blocks everything
  return <Component data={data} />;
}

Good:

async function Page() {
  const dataPromise = fetchData(); // Start immediately
  return <Component dataPromise={dataPromise} />;
}

Rule: Use Promise.all() for independent operations

Bad:

const user = await getUser();
const posts = await getPosts();
const comments = await getComments();

Good:

const [user, posts, comments] = await Promise.all([
  getUser(),
  getPosts(),
  getComments(),
]);

Rule: Start promises at the earliest point

Bad:

function Component() {
  useEffect(() => {
    fetchData().then(setData); // Too late
  }, []);
}

Good:

// In route loader or parent component
const dataPromise = fetchData();

function Component({ dataPromise }) {
  const data = use(dataPromise);
}

Rule: Use Suspense boundaries for streaming

<Suspense fallback={<Skeleton />}>
  <AsyncComponent />
</Suspense>

Category 2: Bundle Size Optimization (CRITICAL)

Rule: Avoid barrel file imports

Bad:

import { Button } from "@/components"; // Pulls entire barrel
import { format } from "date-fns"; // Pulls entire library

Good:

import { Button } from "@/components/ui/button";
import { format } from "date-fns/format";

Rule: Use next/dynamic for heavy components

const HeavyChart = dynamic(() => import("./Chart"), {
  loading: () => <ChartSkeleton />,
  ssr: false,
});

Rule: Defer third-party libraries

// Load analytics only after interaction
const loadAnalytics = () => import("analytics").then((m) => m.init());

useEffect(() => {
  window.addEventListener("click", loadAnalytics, { once: true });
}, []);

Rule: Configure optimizePackageImports

// next.config.js
module.exports = {
  experimental: {
    optimizePackageImports: ["lodash", "date-fns", "@radix-ui/react-icons"],
  },
};

Category 3: Server-Side Performance (HIGH)

Rule: Use React.cache() for request deduplication

import { cache } from "react";

const getUser = cache(async (id: string) => {
  return db.user.findUnique({ where: { id } });
});

Rule: Implement LRU caching for expensive computations

import { LRUCache } from "lru-cache";

const cache = new LRUCache<string, Data>({ max: 100 });

async function getData(key: string) {
  if (cache.has(key)) return cache.get(key);
  const data = await expensiveComputation(key);
  cache.set(key, data);
  return data;
}

Rule: Minimize serialization overhead

Bad:

// Passing entire objects when only ID needed
<ClientComponent user={user} />

Good:

<ClientComponent userId={user.id} />

Category 4: Client-Side Data Fetching (MEDIUM-HIGH)

Rule: Use SWR or React Query for client fetching

import useSWR from "swr";

function Profile({ userId }) {
  const { data, error, isLoading } = useSWR(`/api/user/${userId}`, fetcher);

  if (isLoading) return <Skeleton />;
  if (error) return <Error />;
  return <UserCard user={data} />;
}

Rule: Use lazy state initialization

Bad:

const [state, setState] = useState(expensiveComputation());

Good:

const [state, setState] = useState(() => expensiveComputation());

Rule: Use startTransition for non-urgent updates

import { startTransition } from "react";

function handleSearch(query) {
  startTransition(() => {
    setSearchResults(search(query));
  });
}

Category 5: Re-render Optimization (MEDIUM)

Rule: Narrow state scope

Bad:

function Parent() {
  const [count, setCount] = useState(0);
  return (
    <>
      <Counter count={count} setCount={setCount} />
      <ExpensiveList /> {/* Re-renders on every count change */}
    </>
  );
}

Good:

function Parent() {
  return (
    <>
      <CounterWithState />
      <ExpensiveList />
    </>
  );
}

Rule: Use useMemo for expensive calculations

const sortedItems = useMemo(
  () => items.sort((a, b) => a.name.localeCompare(b.name)),
  [items]
);

Rule: Use useCallback for stable function references

const handleClick = useCallback((id) => {
  setItems((items) => items.filter((item) => item.id !== id));
}, []);

Category 6: Rendering Performance (MEDIUM)

Rule: Use content-visibility for long lists

.list-item {
  content-visibility: auto;
  contain-intrinsic-size: 0 50px;
}

Rule: Wrap SVG animations to prevent layout recalculation

function AnimatedIcon() {
  return (
    <div style={{ contain: "layout" }}>
      <AnimatedSVG />
    </div>
  );
}

Rule: Use conditional rendering over CSS hiding

Bad:

<div style={{ display: isVisible ? "block" : "none" }}>
  <ExpensiveComponent />
</div>

Good:

{
  isVisible && <ExpensiveComponent />;
}

Category 7: JavaScript Performance (LOW-MEDIUM)

Rule: Batch DOM updates

// Use refs for multiple rapid updates
const counterRef = useRef<HTMLSpanElement>(null);

function increment() {
  if (counterRef.current) {
    counterRef.current.textContent = String(++count);
  }
}

Rule: Build index maps for repeated lookups

Bad:

items.forEach((item) => {
  const related = otherItems.find((o) => o.id === item.relatedId);
});

Good:

const otherItemsById = new Map(otherItems.map((o) => [o.id, o]));
items.forEach((item) => {
  const related = otherItemsById.get(item.relatedId);
});

Rule: Use immutable array methods

// Prefer these for predictable React updates
const updated = items.with(index, newValue);
const filtered = items.toSpliced(index, 1);
const sorted = items.toSorted((a, b) => a.name.localeCompare(b.name));

Category 8: Advanced Patterns (LOW)

Rule: Use useSyncExternalStore for external state

const value = useSyncExternalStore(
  store.subscribe,
  store.getSnapshot,
  store.getServerSnapshot
);

Rule: Implement optimistic updates

const [optimisticItems, addOptimisticItem] = useOptimistic(
  items,
  (state, newItem) => [...state, { ...newItem, pending: true }]
);

Quick Reference Checklist

  • No sequential awaits for independent data
  • Using Promise.all() for parallel fetches
  • No barrel file imports
  • Heavy components use dynamic imports
  • Suspense boundaries around async components
  • State scoped to smallest necessary component
  • useMemo/useCallback where beneficial
  • content-visibility for long lists

スコア

総合スコア

85/100

リポジトリの品質指標に基づく評価

SKILL.md

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

+20
LICENSE

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

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

+5
最近の活動

1ヶ月以内に更新

+10
フォーク

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

+5
Issue管理

オープンIssueが50未満

+5
言語

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

+5
タグ

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

+5

レビュー

💬

レビュー機能は近日公開予定です