react icon indicating copy to clipboard operation
react copied to clipboard

[Compiler Bug]: False positive local mutation warning inside filter

Open gaearon opened this issue 1 year ago • 6 comments

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

gaearon avatar Nov 17 '24 20:11 gaearon

Thanks for reporting, definitely a bug.

josephsavona avatar Nov 17 '24 23:11 josephsavona

šŸ˜ŠšŸ‘Œ

ParhamPK03 avatar Nov 18 '24 18:11 ParhamPK03

Bug

aalmanasir avatar Nov 22 '24 09:11 aalmanasir

Hi @gaearon , is this bug fixed ?

sanjai2k1 avatar May 18 '25 16:05 sanjai2k1

Not fixed yet, but I’m working on how we handle function expressions and that work will address this bug.

josephsavona avatar May 18 '25 19:05 josephsavona

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])

Ayc0 avatar May 26 '25 20:05 Ayc0

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...

Git-I985 avatar Nov 02 '25 20:11 Git-I985