Advanced React performance patterns including memoization, code splitting, and render optimization for Google Antigravity.
# React Render Optimization for Google Antigravity
Performance is critical for user experience. Google Antigravity's Gemini 3 helps you identify and fix performance bottlenecks with intelligent suggestions for memoization, code splitting, and render optimization.
## Memoization Strategies
Use React.memo effectively:
```typescript
// components/ExpensiveList.tsx
import { memo, useMemo, useCallback } from "react";
interface Item {
id: string;
name: string;
price: number;
}
interface ItemCardProps {
item: Item;
onSelect: (id: string) => void;
}
const ItemCard = memo(function ItemCard({ item, onSelect }: ItemCardProps) {
console.log(`Rendering ItemCard: ${item.name}`);
return (
<div
className="p-4 border rounded-lg cursor-pointer hover:bg-gray-50"
onClick={() => onSelect(item.id)}
>
<h3 className="font-medium">{item.name}</h3>
<p className="text-gray-600">${item.price.toFixed(2)}</p>
</div>
);
});
interface ItemListProps {
items: Item[];
filterText: string;
}
export function ItemList({ items, filterText }: ItemListProps) {
const filteredItems = useMemo(() => {
console.log("Filtering items...");
return items.filter((item) =>
item.name.toLowerCase().includes(filterText.toLowerCase())
);
}, [items, filterText]);
const handleSelect = useCallback((id: string) => {
console.log(`Selected: ${id}`);
}, []);
const totalValue = useMemo(() => {
return filteredItems.reduce((sum, item) => sum + item.price, 0);
}, [filteredItems]);
return (
<div>
<div className="mb-4 text-sm text-gray-500">
Total: ${totalValue.toFixed(2)} ({filteredItems.length} items)
</div>
<div className="grid gap-4">
{filteredItems.map((item) => (
<ItemCard key={item.id} item={item} onSelect={handleSelect} />
))}
</div>
</div>
);
}
```
## Virtual Scrolling
Handle large lists efficiently:
```typescript
// components/VirtualList.tsx
"use client";
import { useRef, useState, useEffect, useCallback } from "react";
interface VirtualListProps<T> {
items: T[];
itemHeight: number;
renderItem: (item: T, index: number) => React.ReactNode;
overscan?: number;
}
export function VirtualList<T>({
items,
itemHeight,
renderItem,
overscan = 3,
}: VirtualListProps<T>) {
const containerRef = useRef<HTMLDivElement>(null);
const [scrollTop, setScrollTop] = useState(0);
const [containerHeight, setContainerHeight] = useState(0);
useEffect(() => {
const container = containerRef.current;
if (!container) return;
const resizeObserver = new ResizeObserver((entries) => {
setContainerHeight(entries[0].contentRect.height);
});
resizeObserver.observe(container);
return () => resizeObserver.disconnect();
}, []);
const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
setScrollTop(e.currentTarget.scrollTop);
}, []);
const totalHeight = items.length * itemHeight;
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
const endIndex = Math.min(
items.length,
Math.ceil((scrollTop + containerHeight) / itemHeight) + overscan
);
const visibleItems = items.slice(startIndex, endIndex);
const offsetY = startIndex * itemHeight;
return (
<div
ref={containerRef}
className="overflow-auto h-full"
onScroll={handleScroll}
>
<div style={{ height: totalHeight, position: "relative" }}>
<div
style={{
position: "absolute",
top: offsetY,
left: 0,
right: 0,
}}
>
{visibleItems.map((item, index) => (
<div key={startIndex + index} style={{ height: itemHeight }}>
{renderItem(item, startIndex + index)}
</div>
))}
</div>
</div>
</div>
);
}
```
## Code Splitting with Dynamic Imports
Load components on demand:
```typescript
// app/dashboard/page.tsx
import { Suspense, lazy } from "react";
import dynamic from "next/dynamic";
const HeavyChart = dynamic(() => import("@/components/HeavyChart"), {
loading: () => <div className="h-64 animate-pulse bg-gray-200 rounded" />,
ssr: false,
});
const DataTable = lazy(() => import("@/components/DataTable"));
export default function DashboardPage() {
return (
<div className="space-y-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
<section>
<h2 className="text-lg font-medium mb-4">Analytics</h2>
<HeavyChart />
</section>
<section>
<h2 className="text-lg font-medium mb-4">Recent Data</h2>
<Suspense fallback={<TableSkeleton />}>
<DataTable />
</Suspense>
</section>
</div>
);
}
function TableSkeleton() {
return (
<div className="space-y-2">
{[...Array(5)].map((_, i) => (
<div key={i} className="h-12 animate-pulse bg-gray-200 rounded" />
))}
</div>
);
}
```
## Debounced State Updates
Optimize frequent updates:
```typescript
// hooks/useDebounce.ts
import { useState, useEffect, useRef, useCallback } from "react";
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
export function useDebouncedCallback<T extends (...args: unknown[]) => void>(
callback: T,
delay: number
): T {
const timeoutRef = useRef<NodeJS.Timeout>();
const debouncedCallback = useCallback(
(...args: Parameters<T>) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
callback(...args);
}, delay);
},
[callback, delay]
) as T;
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return debouncedCallback;
}
```
```typescript
// components/SearchInput.tsx
"use client";
import { useState, useTransition } from "react";
import { useDebounce, useDebouncedCallback } from "@/hooks/useDebounce";
interface SearchInputProps {
onSearch: (query: string) => void;
}
export function SearchInput({ onSearch }: SearchInputProps) {
const [query, setQuery] = useState("");
const [isPending, startTransition] = useTransition();
const debouncedQuery = useDebounce(query, 300);
const handleSearch = useDebouncedCallback((value: string) => {
startTransition(() => {
onSearch(value);
});
}, 300);
return (
<div className="relative">
<input
type="text"
value={query}
onChange={(e) => {
setQuery(e.target.value);
handleSearch(e.target.value);
}}
placeholder="Search..."
className="w-full px-4 py-2 border rounded-lg"
/>
{isPending && (
<div className="absolute right-3 top-1/2 -translate-y-1/2">
<div className="w-4 h-4 border-2 border-primary-500 border-t-transparent rounded-full animate-spin" />
</div>
)}
</div>
);
}
```
## Optimized Context Pattern
Prevent unnecessary re-renders with context:
```typescript
// contexts/OptimizedContext.tsx
"use client";
import { createContext, useContext, useMemo, useState } from "react";
interface AppState {
user: { id: string; name: string } | null;
theme: "light" | "dark";
notifications: number;
}
interface AppActions {
setUser: (user: AppState["user"]) => void;
toggleTheme: () => void;
incrementNotifications: () => void;
}
const AppStateContext = createContext<AppState | null>(null);
const AppActionsContext = createContext<AppActions | null>(null);
export function AppProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = useState<AppState>({
user: null,
theme: "light",
notifications: 0,
});
const actions = useMemo<AppActions>(() => ({
setUser: (user) => setState((prev) => ({ ...prev, user })),
toggleTheme: () =>
setState((prev) => ({
...prev,
theme: prev.theme === "light" ? "dark" : "light",
})),
incrementNotifications: () =>
setState((prev) => ({
...prev,
notifications: prev.notifications + 1,
})),
}), []);
return (
<AppStateContext.Provider value={state}>
<AppActionsContext.Provider value={actions}>
{children}
</AppActionsContext.Provider>
</AppStateContext.Provider>
);
}
export function useAppState() {
const context = useContext(AppStateContext);
if (!context) throw new Error("useAppState must be used within AppProvider");
return context;
}
export function useAppActions() {
const context = useContext(AppActionsContext);
if (!context) throw new Error("useAppActions must be used within AppProvider");
return context;
}
export function useAppSelector<T>(selector: (state: AppState) => T): T {
const state = useAppState();
return useMemo(() => selector(state), [state, selector]);
}
```
## Best Practices
1. **Profile before optimizing** - Use React DevTools to identify bottlenecks
2. **Memoize expensive computations** - Use useMemo for derived data
3. **Stabilize callbacks** - Use useCallback for event handlers passed as props
4. **Split contexts** - Separate frequently changing data from static data
5. **Virtualize long lists** - Use windowing for large datasets
React performance optimization with Google Antigravity ensures smooth, responsive applications with intelligent profiling suggestions.This react prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their react implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For react projects, consider mentioning your framework version, coding style, and any specific libraries you're using.