| name | react-best-practices |
| description | React performance patterns for this D3+SVG visualization project. Apply when writing React components, hooks, state management, or reviewing code for performance issues. |
React Best Practices
Source: vercel-labs/agent-skills
Avoid Barrel Imports (CRITICAL)
Import directly from source files, not barrel files (index.js). Barrel files can load thousands of modules.
import { Check, X } from "lucide-react";
import Check from "lucide-react/dist/esm/icons/check";
Functional setState (MEDIUM)
Use functional updates when new state depends on previous state. Prevents stale closures, keeps callbacks stable.
setItems([...items, newItem]);
setItems((curr) => [...curr, newItem]);
Lazy State Initialization (MEDIUM)
Pass function to useState for expensive initial values. Without it, initializer runs every render.
useState(JSON.parse(localStorage.getItem("x") || "{}"));
useState(() => JSON.parse(localStorage.getItem("x") || "{}"));
Derived State (MEDIUM)
Subscribe to processed boolean state, not raw continuous values.
const width = useWindowWidth();
const isMobile = width < 768;
const isMobile = useMediaQuery("(max-width: 767px)");
Narrow Effect Dependencies (LOW)
Use primitives in dependency arrays, not objects.
useEffect(() => { ... }, [user])
useEffect(() => { ... }, [user.id])
Animate SVG Wrapper (LOW)
Wrap SVG in <div> for CSS animations. Many browsers lack hardware acceleration for SVG animations.
<svg className="animate-spin">...</svg>
<div className="animate-spin"><svg>...</svg></div>
Hoist Static JSX (LOW)
Extract static JSX outside components. Especially valuable for large static SVG nodes.
function Icon() {
const svg = <svg>...</svg>;
return svg;
}
const svg = <svg>...</svg>;
function Icon() {
return svg;
}
Explicit Conditional Rendering (LOW)
Use ternary instead of && to prevent rendering 0 or NaN.
{
count && <span>{count}</span>;
}
{
count > 0 ? <span>{count}</span> : null;
}
Set/Map for Lookups (LOW-MEDIUM)
Use Set.has() instead of Array.includes() for repeated lookups. O(1) vs O(n).
const ids = ["a", "b", "c"];
items.filter((x) => ids.includes(x.id));
const ids = new Set(["a", "b", "c"]);
items.filter((x) => ids.has(x.id));
Event Handler Refs (LOW)
Store callbacks in refs when used in effects that shouldn't re-subscribe on callback changes.
const handlerRef = useRef(handler);
useEffect(() => {
handlerRef.current = handler;
});
useEffect(() => {
const listener = (e) => handlerRef.current(e);
window.addEventListener("resize", listener);
return () => window.removeEventListener("resize", listener);
}, []);