What you'll learn
- Paths for hot lists, heavy selectors, loop cost and profile-first work
- Match JS costs like multi-pass arrays and eager state init
- Combine loops, lazy init, memoized selectors and stable objects
- Profile before micro-optimizing
This page covers practical JavaScript-level optimizations inside React components, based on patterns shown in Vercel's Introducing: React Best Practices (opens in a new tab) and react-best-practices examples. The goal is not micro-optimizing everything. It is eliminating repeated work that compounds under real user interaction.
Use the path picker when you know the situation. Use the cost matcher when the Profiler points at JS self-time. For re-render identity rules, see Stop Unnecessary Re-renders.

Pick a JS performance path
Try it: JS performance path
Pick your situation. You get an ordered approach, why it fits, and a first-week plan.
Your path
Cut allocations and passes on the hot list path
Lists that update often amplify multi-pass filters and new object props. Fix the JS cost before blaming React.
- Profile before optimizing
Confirm self-time is in your JS, not network.
- Combine loop iterations
One pass over large arrays when possible.
- Avoid object creation in render
Stop allocating props every render.
- Stop Unnecessary Re-renders
After JS is cheap, fix memo identity issues.
First week
Profile one chat or table screen. Combine multi-pass stats into one loop. Stabilize style and query option objects.
If the Profiler bar is network, fix waterfalls first. This page is for JS that runs during render.
Checkpoint
You suspect a multi-filter stats helper is slow. What first?
Pick an answer, or press A, B, C on your keyboard.
Match a JS cost

Try it: match a JS cost
Choose the cost you suspect. The matcher points to a primary pattern and an optional alternate.
The cost
The same large array is filtered or mapped many times to build related stats.
Start here
Combine loop iterationsOne pass builds the same counts with fewer temporary arrays and less GC pressure.
Also consider
Profile before optimizingConfirm the list is hot before rewriting readable multi-pass code.
Related: Performance hub
The goal is not micro-optimizing everything. It is removing repeated work that compounds under real interaction.
Key takeaway
If the Profiler bar is network, fix waterfalls first. This page is for JS that runs during render.
Combining loop iterations

A real pattern from Vercel examples: chat UIs repeatedly scanning the same messages list for different metrics, badges, and derived groups.
When the list is large (or updated frequently), this removes repeated iteration cost and GC pressure from intermediate arrays.
Lazy state initialization
Vercel's real-world example pattern: parsing local storage config on every render. The re-render article covers the same habit in the memo rules; this section keeps the JS-focused example.
The non-lazy version runs JSON.parse(...) on every re-render, but React ignores that value after the first render. That is wasted CPU.
Memoizing stable selectors
Inline sorting and filtering creates fresh arrays every render, even if inputs did not change.
Use React DevTools Profiler with "Why did this render?" enabled to confirm the selector output was triggering re-renders.
Avoiding object creation in render

Common render-time allocation traps:
Fix guide:
- Inline style props: hoist constant objects to module scope when static (same idea for CSS Modules or vanilla
classNamestrings: avoid allocating new style objects or template strings every render when the value is static) - Hook config objects: memoize values and functions used as options, or hoist static option objects
new RegExp()in render: hoist a module-level regex when the pattern is fixed
Checkpoint
A memoized child still re-renders because of style={{ margin: 0 }}. What helps?
Pick an answer, or press A, B, C on your keyboard.
How to profile before optimizing
Use React DevTools Profiler first, then optimize only measured hotspots.
// Recommended profiling routine:
// 1) Open React DevTools -> Profiler tab
// 2) Record while performing a realistic interaction
// 3) Sort by "Self time" and "Render duration"
// 4) Check "Why did this render?" for noisy components
// 5) Apply a targeted optimization
// 6) Re-profile and confirm the change helpedIf performance did not improve measurably, revert the change and keep the simpler code.
The key habit
Profile first. Change the hottest bar. Re-profile. Revert noise.
JS performance checklist
- I profiled a realistic interaction before rewriting helpers
- Hot multi-pass array work is combined when it matters
- Expensive useState initializers are lazy
- Expensive derived arrays use useMemo with clear deps
- Static style and options objects are not recreated every render
- Unmeasured memo was not added "just in case"
Further reading
- Stop Unnecessary Re-renders
- React Performance Optimization
- Bundle Size Optimization
- Eliminating Async Waterfalls
- Proficiency with Hooks
Conclusion
JavaScript cost during render is often the quiet half of a "React is slow" complaint. Fix the work, then fix the identity rules.
The key takeaway
Eliminate repeated work that compounds under real interaction. Leave cold paths alone.
Check your understanding
If the Profiler bar is network waterfalls, what should you do first on this page?
Pick an answer, or press A, B, C on your keyboard.
Recap
What to remember from this article
Sections read
0
Questions
0
none answered yet
Quiz
0
not taken yet
Up next: NX Introduction & Architecture · 4 min
Continue