[Compiler Bug]: False positive local mutation warning inside filter
What kind of issue is this?
- [ ] React Compiler core (the JS output is incorrect, or your app works incorrectly after optimization)
- [ ] babel-plugin-react-compiler (build issue installing or using the Babel plugin)
- [x] eslint-plugin-react-compiler (build issue installing or using the eslint plugin)
- [ ] react-compiler-healthcheck (build issue installing or using the healthcheck script)
Link to repro
https://playground.react.dev/#N4Igzg9grgTgxgUxALhASwLYAcIwC4AEASggIZyEBmMEGBA5DGRfQDoB2HCAHjvgZSjsKaCOwIBhWjnYJ2eABTA0eBBjABfAJQFgHAgThiwhE1EqUCAXmLM8AOihgEAWTUQFCnVYB8u-QYEADYIhGhgUhBB1gKkQc4BBkbsJgSQGAgAkqrqMSpqYImB9pRoQaowCnCkTgjWfnrigc1ollU1ziUQEDqNzf0E4ZHRNngwUAhFzRpTgUx4sOJjE7PaHEWtBArpWTlg9iHsAOZ4ABYEfgAMvbPzi7o72QUANIMR3UEzTQZfP68A2vl1ABdLQBO4wcQAHgAJmgAG4EAD0Pg4XxAGiAA
Repro steps
import React from 'react'
export function Component({items}) {
const stuff = React.useMemo(() => {
let isCool = false
const someItems = items
.filter(cause => {
if (cause.foo) {
isCool = true
}
return true
})
if (someItems.length > 0) {
return {someItems, isCool}
}
}, [items])
return <div />
}
Getting:
InvalidReact: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead. Variable `isCool` cannot be reassigned after render (9:9)
But it's not used after render. Curiously, changing the if condition to something that doesn't refer to someItems helps.
How often does this bug happen?
Every time
What version of React are you using?
18.2.0
What version of React Compiler are you using?
19.0.0-beta-a7bf2bd-20241110
Thanks for reporting, definitely a bug.
šš
Bug
Hi @gaearon , is this bug fixed ?
Not fixed yet, but Iām working on how we handle function expressions and that work will address this bug.
FYI I noticed the bug with this codepath ā view in playground
It was the same code, but instead of a .filter it's a .map. Maybe this doesn't add that much value, sorry for the added noise
(I was able to replicate using [email protected])
same
export function PieChart({ diameter = 200, className, ...props }: PieChartProps) {
const radius = diameter / 2;
const circumference = (Math.PI * 2 * radius) / 2;
let offset = 0;
const slices = (props.slices || [])
.filter((i) => i > 0)
.map((i, key) => {
const sliceWidth = i * (circumference / 100);
const slice = (
<circle
key={key}
r={radius / 2}
cx={radius}
cy={radius}
strokeWidth={radius}
strokeDashoffset={offset}
strokeDasharray={`${sliceWidth} ${circumference}`}
/>
);
/*
ESLint:
Error: Cannot reassign variable after render completes
Reassigning `offset` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead.
/src/blocks/components/PieChart/index.tsx:32:7
30 | />
31 | );
> 32 | offset -= sliceWidth;
| ^^^^^^ Cannot reassign `offset` after render completes
33 | return slice; // its not AFTER !!!!
34 | });
35 |
(react-hooks/immutability)
*/
offset -= sliceWidth;
return slice;
});
return (
<svg
className={classNames(styles.pieChart, className)}
height={diameter}
width={diameter}
viewBox={`0 0 ${diameter} ${diameter}`}
>
<circle className={styles.pieChartBgCircle} r={radius} cx={radius} cy={radius} />
<g className={styles.pieChartSlicesContainer}>{slices}</g>
<circle className={styles.pieChartHole} r={radius / 2} cx={radius} cy={radius} />
</svg>
);
}
2 years...