Skip to content

react-rendering-performance

<!-- Loaded by performance-optimization-engineer when task involves rendering, layout, CLS, hydration, or visual performance -->

From plugin
vexjoy-agent
413198 skills198 agents10 commands86 hooks
Install
$ npx -y skills add notque/vexjoy-agent --agent claude-code

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

<!-- Loaded by performance-optimization-engineer when task involves rendering, layout, CLS, hydration, or visual performance -->

Agent definition

react-rendering-performance.md

React Rendering Performance Reference

<!-- Loaded by performance-optimization-engineer when task involves rendering, layout, CLS, hydration, or visual performance -->

CSS content-visibility for Long Lists

**Impact:** HIGH — faster initial render; 10x improvement for lists of 1000+ items

`content-visibility: auto` lets the browser skip layout and paint for off-screen items. For a list of 1000 messages, the browser skips those calculations for ~990 off-screen items. `contain-intrinsic-size` provides a placeholder size so the scrollbar remains accurate without forcing layout of every item.

**Use:**

.message-item {
  content-visibility: auto;
  contain-intrinsic-size: 0 80px; /* estimated item height */
}
function MessageList({ messages }: { messages: Message[] }) {
  return (
    <div className="overflow-y-auto h-screen">
      {messages.map(msg => (
        <div key={msg.id} className="message-item">
          <Avatar user={msg.author} />
          <div>{msg.content}</div>
        </div>
      ))}
    </div>
  )
}

---

Hoist Static JSX Outside Render

**Impact:** LOW — avoids object re-creation on every render

JSX evaluates to object creation. Static elements that never change can be declared once at module scope rather than recreated on every render call. This is especially valuable for large static SVG nodes.

**Instead of:**

function Container() {
  // New object created every render
  return (
    <div>
      {loading && <div className="animate-pulse h-20 bg-gray-200" />}
    </div>
  )
}

**Use:**

const loadingSkeleton = (
  <div className="animate-pulse h-20 bg-gray-200" />
)

function Container() {
  return (
    <div>
      {loading && loadingSkeleton}
    </div>
  )
}

Note: If React Compiler is enabled in your project, it automatically hoists static JSX — manual hoisting is unnecessary in that case.

---

SVG Precision Optimization

**Impact:** LOW — reduces file size

SVG coordinate precision beyond 1 decimal place is rarely visible at typical display sizes. Reducing precision shrinks file size with no perceptible quality loss. The optimal precision depends on the viewBox size.

**Instead of:**

<path d="M 10.293847 20.847362 L 30.938472 40.192837" />

**Use:**

<path d="M 10.3 20.8 L 30.9 40.2" />

Automate with SVGO:

npx svgo --precision=1 --multipass icon.svg

---

Hydration Mismatch Prevention

**Impact:** MEDIUM — avoids visual flicker and hydration errors

When rendering content that depends on client-side storage (localStorage, cookies), a naive `useEffect` approach causes a visible flash: the server renders a default value, hydration completes, then the effect runs and updates to the real value. Injecting a synchronous inline script that runs before React hydrates avoids both the SSR error and the flash.

**Instead of (SSR error):**

function ThemeWrapper({ children }: { children: ReactNode }) {
  const theme = localStorage.getItem('theme') || 'light' // throws on server
  return <div className={theme}>{children}</div>
}

**Instead of (visible flash):**

function ThemeWrapper({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState('light')
  useEffect(() => {
    const stored = localStorage.getItem('theme')
    if (stored) setTheme(stored) // runs after hydration — user sees flash
  }, [])
  return <div className={theme}>{children}</div>
}

**Use (no flash, no hydration error):**

function ThemeWrapper({ children }: { children: ReactNode }) {
  return (
    <>
      <div id="theme-wrapper">
        {children}
      </div>
      <script
        dangerouslySetInnerHTML={{
          __html: `
            (function() {
              try {
                var theme = localStorage.getItem('theme') || 'light';
                var el = document.getElementById('theme-wrapper');
                if (el) el.className = theme;
              } catch (e) {}
            })();
          `,
        }}
      />
    </>
  )
}

The inline script executes synchronously before the first paint, so the DOM already has the correct value when React hydrates — no mismatch, no flash.

Useful for: theme toggles, user preferences, authentication states, locale settings.

---

Script defer and async Placement

**Impact:** HIGH — eliminates render-blocking

Script tags without `defer` or `async` block HTML parsing while downloading and executing, delaying First Contentful Paint and Time to Interactive. Adding the correct attribute costs nothing and gains significant render-blocking elimination.

  • `defer`: downloads in parallel, executes after HTML parsing, maintains order — use for DOM-dependent scripts
  • `async`: downloads in parallel, executes immediately when ready, no order guarantee — use for independent scripts like analytics

**Instead of:**

<script src="https://example.com/analytics.js"></script>
<script src="/scripts/utils.js"></script>

**Use:**

<script src="https://example.com/analytics.js" async></script>
<script src="/scripts/utils.js" defer></script>

In React:

export default function Document() {
  return (
    <html>
      <head>
        <script src="https://example.com/analytics.js" async />
        <script src="/scripts/utils.js" defer />
      </head>
      <body>{/* content */}</body>
    </html>
  )
}

Next.js variant using the `Script` component with `strategy` prop:

import Script from 'next/script'

<Script src="https://example.com/analytics.js" strategy="afterInteractive" />
<Script src="/scripts/utils.js" strategy="beforeInteractive" />

---

Explicit Conditional Rendering

**Impact:** LOW — prevents rendering `0` or `NaN` as visible text

The `&&` operator renders any falsy value that is not `false`, `null`, or `undefined` — notably `0` and `NaN` both render as visible text. Explicit ternary operators avoid this class of bug entirely.

**Instead of:**

function Badge({ count }: {
Read more
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. AI agents skip steps. "Looks correct" replaces running tests. "Trivial change" replaces verification.

Get the whole plugin, auto-invoked