---
title: "React component re-renders with unchanged props (smooth/react-wasted-renders)"
description: "smooth/react-wasted-renders: A component that re-renders when every prop is equal by value, with no state or context change, produced the same output for…"
canonical: https://void.parthkapoor.me/rules/smooth/react-wasted-renders
lastModified: 2026-09-16
---

# React component re-renders with unchanged props

`smooth/react-wasted-renders` · severity **warn** · category Smoothness · detected by `void smooth` and `void audit`

## Why it matters

A component that re-renders when every prop is equal by value, with no state or context change, produced the same output for nothing. Usually the props are rebuilt each render (inline objects, arrays, arrow functions) or a parent re-renders the whole subtree. The check compares values, so treat each hit as a memo candidate to confirm, not proof.

## How to fix it

Read `changedByReference` in the evidence: hoist constant objects out of render, wrap handlers in useCallback and derived values in useMemo, then memo() the component. Better still, move the state that changes down to the component that needs it, or enable the React Compiler.

## Example

```
const rowStyle = { height: 60 };            // hoisted: same object every render
const onSelect = useCallback(() => pick(i), [i]);
<Row style={rowStyle} onSelect={onSelect} />  // with Row = memo(Row)
```

## References

- https://react.dev/reference/react/memo
- https://react.dev/reference/react/useCallback
- https://react.dev/learn/react-compiler

## More smoothness rules

`void smooth` reports 18 rules in this category. How the page feels after it loads: dropped frames during a scripted scroll, long animation frames, INP of real clicks, shifts after input, animated layout properties, idle rAF loops and reduced-motion handling.

- `reduced-motion-ignored` Animations keep running with prefers-reduced-motion — [smooth/reduced-motion-ignored](https://void.parthkapoor.me/rules/smooth/reduced-motion-ignored)
- `raf-loop-idle` requestAnimationFrame loop runs while idle — [smooth/raf-loop-idle](https://void.parthkapoor.me/rules/smooth/raf-loop-idle)
- `scroll-timeline-no-fallback` Content is invisible without scroll-driven-animation support — [smooth/scroll-timeline-no-fallback](https://void.parthkapoor.me/rules/smooth/scroll-timeline-no-fallback)
- `multiple-webgl-contexts` Multiple WebGL contexts — [smooth/multiple-webgl-contexts](https://void.parthkapoor.me/rules/smooth/multiple-webgl-contexts)
- `react-commits-on-scroll` React re-renders while the page scrolls — [smooth/react-commits-on-scroll](https://void.parthkapoor.me/rules/smooth/react-commits-on-scroll)
- `react-render-storm` One React commit re-renders hundreds of components — [smooth/react-render-storm](https://void.parthkapoor.me/rules/smooth/react-render-storm)
- `react-idle-commits` React keeps committing while the page is idle — [smooth/react-idle-commits](https://void.parthkapoor.me/rules/smooth/react-idle-commits)
- `react-no-names` React component names are minified — [smooth/react-no-names](https://void.parthkapoor.me/rules/smooth/react-no-names)

Detected by `void smooth` and `void audit`. Explain it in a terminal: `void rules smooth/react-wasted-renders`
