Back to Re-render Optimization

Use Lazy State Initialization

reacthooksuseStateperformanceinitialization
28.0k🕒 2026-06-10Source ↗

Install this skill

npx skills add vercel-labs/agent-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Lazy state initialization in React prevents expensive computations from executing on every component render. By passing a function rather than a direct value to the useState hook, React invokes that function only during the initial mounting phase. This optimization is critical when the initial state depends on synchronous blocking operations, such as parsing complex JSON objects from localStorage, constructing large search indexes from props, or calculating expensive data structures. Without this pattern, the application performs redundant work during every update cycle triggered by props or state changes, which can lead to noticeable latency or frame drops in performance-sensitive applications. Implementing this function wrapper ensures that heavy logic stays scoped to the birth of the component, preserving system resources while maintaining clean, predictable state management across the lifecycle of your UI components.

When to Use This Skill

  • Parsing local storage strings on app startup
  • Generating large filter or search indexes from incoming props
  • Initializing complex class instances or data mapping tables
  • Reading computed values from the DOM during component mount

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • how to optimize expensive useState initializers
  • stop useState from running on every render
  • perform expensive calculation only once during state setup
  • lazy initialization of state in React
  • fix performance lag when initializing state from localStorage

What this skill does

  • Defers execution of initializer logic until the first mount
  • Eliminates repeated execution of heavy functions on subsequent renders
  • Optimizes performance for browser storage data retrieval
  • Reduces CPU overhead for data structure creation
  • Ensures consistent state initialization without side effects

When not to use it

  • Initializing simple primitive values like strings, numbers, or booleans
  • Referencing existing props directly when no computation is involved
  • Creating empty object or array literals

Example workflow

  1. Identify a useState hook that consumes a high-latency calculation
  2. Wrap the calculation logic inside an arrow function
  3. Pass this anonymous function as an argument to the useState hook
  4. Verify that the computation logic logs to the console only once
  5. Confirm the UI renders correctly on subsequent state updates

Prerequisites

  • Basic knowledge of React hooks
  • Understanding of the component render cycle

Pitfalls & limitations

  • !Over-optimizing trivial operations that perform worse due to function closure overhead
  • !Accidentally referencing variables inside the function that change but should remain constant
  • !Adding unnecessary complexity to codebases where performance bottlenecks do not exist

FAQ

Does this work with useReducer?
Yes, useReducer supports a third argument for lazy initialization, which functions identically to this pattern.
Will my state update if I use a function?
The function only runs on the initial mount; subsequent state updates via the setter function work exactly as expected.
Is it bad to use this everywhere?
It adds unnecessary boilerplate for simple assignments; only use it when the initialization logic itself is demonstrably expensive.
Can I perform side effects inside the initializer?
No, the initializer must be a pure function that returns a value; use useEffect for side effects.

How it compares

Unlike manual initialization or simple assignments, lazy initialization provides a native React mechanism to gate-keep execution, ensuring the logic is strictly scoped to the component's mounting phase.

Source & trust

28k stars🕒 Updated 2026-06-10
📄 Full skill instructions — original source: vercel-labs/agent-skills
## Use Lazy State Initialization

Pass a function to useState for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once.

**Incorrect (runs on every render):**

function FilteredList({ items }: { items: Item[] }) {
// buildSearchIndex() runs on EVERY render, even after initialization
const [searchIndex, setSearchIndex] = useState(buildSearchIndex(items))
const [query, setQuery] = useState('')

// When query changes, buildSearchIndex runs again unnecessarily
return <SearchResults index={searchIndex} query={query} />
}

function UserProfile() {
// JSON.parse runs on every render
const [settings, setSettings] = useState(
JSON.parse(localStorage.getItem('settings') || '{}')
)

return <SettingsForm settings={settings} onChange={setSettings} />
}


**Correct (runs only once):**

function FilteredList({ items }: { items: Item[] }) {
// buildSearchIndex() runs ONLY on initial render
const [searchIndex, setSearchIndex] = useState(() => buildSearchIndex(items))
const [query, setQuery] = useState('')

return <SearchResults index={searchIndex} query={query} />
}

function UserProfile() {
// JSON.parse runs only on initial render
const [settings, setSettings] = useState(() => {
const stored = localStorage.getItem('settings')
return stored ? JSON.parse(stored) : {}
})

return <SettingsForm settings={settings} onChange={setSettings} />
}


Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations.

For simple primitives (useState(0)), direct references (useState(props.value)), or cheap literals (useState({})), the function form is unnecessary.

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/rerender-lazy-state-init/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/vercel-labs/agent-skills/rerender-lazy-state-init/SKILL.md
  • Cursor: ~/.cursor/skills/vercel-labs/agent-skills/rerender-lazy-state-init/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/vercel-labs/agent-skills/rerender-lazy-state-init/SKILL.md

🚀 Install with CLI:
npx skills add vercel-labs/agent-skills

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid re-render optimization issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Re-render Optimization and is published by Vercel Engineering, maintained in vercel-labs/agent-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.