Loading...
Loading...
Comprehensive React and Next.js performance optimization guide. Covers waterfall elimination, bundle size reduction, server-side optimization, re-render prevention, and rendering performance. Use when building, reviewing, or optimizing React/Next.js applications for speed.
npx skill4agent add s-hiraoku/synapse-a2a react-performanceawait// BAD: Sequential — total time = fetch1 + fetch2
async function Page() {
const user = await getUser();
const posts = await getPosts(user.id);
return <Feed user={user} posts={posts} />;
}
// GOOD: Parallel where possible
async function Page() {
const userPromise = getUser();
const postsPromise = getPosts(); // if independent
const [user, posts] = await Promise.all([userPromise, postsPromise]);
return <Feed user={user} posts={posts} />;
}<Suspense>export default function Page() {
return (
<main>
<Header /> {/* instant */}
<Suspense fallback={<Skeleton />}>
<SlowDataSection /> {/* streams in */}
</Suspense>
</main>
);
}async function Dashboard() {
const userPromise = getUser();
const settingsPromise = getSettings(); // independent
const user = await userPromise;
const postsPromise = getPosts(user.id); // depends on user
const [settings, posts] = await Promise.all([settingsPromise, postsPromise]);
return <View user={user} settings={settings} posts={posts} />;
}// BAD: Pulls entire library
import { Button } from '@/components';
import { format } from 'date-fns';
// GOOD: Tree-shakeable
import { Button } from '@/components/ui/button';
import { format } from 'date-fns/format';import dynamic from 'next/dynamic';
const Chart = dynamic(() => import('@/components/chart'), {
loading: () => <ChartSkeleton />,
ssr: false, // skip SSR for client-only components
});
const Editor = dynamic(() => import('@/components/editor'), {
loading: () => <EditorSkeleton />,
});// BAD: Blocks hydration
import { analytics } from 'heavy-analytics';
analytics.init();
// GOOD: Load after hydration
useEffect(() => {
import('heavy-analytics').then(({ analytics }) => analytics.init());
}, []);function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
const router = useRouter();
return (
<Link
href={href}
onMouseEnter={() => router.prefetch(href)}
onFocus={() => router.prefetch(href)}
>
{children}
</Link>
);
}React.cache()import { cache } from 'react';
export const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } });
});
// Called in layout.tsx AND page.tsx — only one DB query// BAD: Serializes entire user object
<ClientAvatar user={user} />
// GOOD: Pass only what's needed
<ClientAvatar name={user.name} avatarUrl={user.avatarUrl} />after()import { after } from 'next/server';
export async function POST(request: Request) {
const data = await processRequest(request);
after(async () => {
await logAnalytics(data);
await sendNotification(data);
});
return Response.json(data); // returns immediately
}// BAD: Extra render cycle
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);
useEffect(() => setCount(items.length), [items]);
// GOOD: Derive during render
const [items, setItems] = useState([]);
const count = items.length;// BAD: New function every render
<Button onClick={() => setCount(count + 1)} />
// GOOD: Stable reference
<Button onClick={() => setCount(c => c + 1)} />// BAD: Object reference changes every render
useEffect(() => { ... }, [config]);
// GOOD: Primitive values are stable
useEffect(() => { ... }, [config.apiUrl, config.timeout]);// BAD: Runs every render
const [data, setData] = useState(expensiveParse(raw));
// GOOD: Runs only on mount
const [data, setData] = useState(() => expensiveParse(raw));const ExpensiveList = memo(function ExpensiveList({ items }: { items: Item[] }) {
return items.map(item => <ComplexItem key={item.id} item={item} />);
});startTransitionconst [isPending, startTransition] = useTransition();
function handleSearch(query: string) {
setInputValue(query); // urgent: update input
startTransition(() => setResults(search(query))); // deferrable: update results
}content-visibility.list-item {
content-visibility: auto;
contain-intrinsic-size: 0 80px;
}// BAD: Recreated every render
function Layout({ children }) {
return (
<div>
<footer><p>Copyright 2026</p></footer>
{children}
</div>
);
}
// GOOD: Created once
const footer = <footer><p>Copyright 2026</p></footer>;
function Layout({ children }) {
return <div>{footer}{children}</div>;
}&&0""// BAD: Renders "0" when count is 0
{count && <Badge count={count} />}
// GOOD: Explicit boolean check
{count > 0 ? <Badge count={count} /> : null}| Issue | Fix | Priority |
|---|---|---|
| Sequential fetches | | CRITICAL |
| Barrel imports | Direct path imports | CRITICAL |
| Large initial bundle | | CRITICAL |
| Redundant DB calls | | HIGH |
| Over-serialized props | Pass primitives only | HIGH |
| Derived state in useEffect | Compute during render | MEDIUM |
| Unstable callbacks | | MEDIUM |
| Long lists | Virtualization + | MEDIUM |
| Non-urgent updates | | MEDIUM |