react icon indicating copy to clipboard operation
react copied to clipboard

[Compiler Bug]: React fails to rerender list items when using compiler with zustand store

Open MarkusWendorf opened this issue 8 months ago • 2 comments

What kind of issue is this?

  • [x] 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)
  • [ ] 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/#N4Igzg9grgTgxgUxALhASwLYAcIwC4AEwBcMCAhnggQL4EBmMEGBA5AF5Rh7kB2AJqwDcAHV6Yc+IgS4IAygAtyAG2UQA7rQZMWHLjwEB6MuTh5DYJao3CxYhAA9JhOBF7cZYeQjx40vAHMwAgBeEhMqAAoASkjIrzwAGgIAn2jQgD4CSOAxAgY0ZSoYMGQiGkS8gjwIAIDlBAAxQuKyyPoWhBgASX50kKzc3nz813dCDqKu4LDUvBiAOknisFFhkYScgqmSsuIFg+Xp5IBtI57+AF0ygEJzsDPOi8utGmi1-IqqueadtvPev1BlV8mQ8LBhnNFvdHjtepcPrRKrw3u87LxHM4GFBeGY0G5PE0nnIfH5AmAYkQqmCIYSSb5-EFIiC6VY1OpmesRtliAlfsVkjU6g1+V1kmQ+U8wMkfk9kvdaECeSzuZKdsjudyhfUieqVSMJT5RSUNZr8rK9VzNfdTdy3izolU0Sj0WMPBAsH43DMCCcqsQ0PwyqwwIyGqwkf6CIHg-RyBhCgBPCNfdYBoNsVxQLDhyNp6MZ1gBJjZlOm9PB9RoPAKAC0-FqZbECPRmNwhH4CDjUCK2NxXuGAEEsFhKUNRt7CMQLQLqrUdcb5VKtGFZMb6WSmc7qT5aZzuQAefhoABuGX1wA9A7ACww5FHkSwTCwYCV+7NBAPAGEFGgsPruQAawQRMQmAJ8PRvQMaAAkYEF4cgACMGn4MCZy6R9nygvoYKtM03C-ZQ0DgQCwO1EUnlwj8RhPFQoAQMCIJfBZoNgwxzzwghomiXD9QPJ8EAyYAACk5AAeQAOQWbgYEZNB6ETdopWSXge2UZIACYeIPQwBI4w9DGPM8nTWXjeHoHE8QJH8-y2eCkJQ5ICKIkjklo5R6MVKl1hpGBhnffIj1PAhnOI0jgEpAYQt4Qiwsidz6J4-TNWABKEDoYB7OQhB+AIAB+NgspQiNg2PMAHJy1gqJGHSjOS51cJAGggA

Repro steps

When running this example: https://stackblitz.com/edit/vitejs-vite-tnyshyjv?file=package.json,src%2FApp.jsx

Clicking the list items should toggle the text from disabled to enabled. It only does when 'use no memo'; is used.

The getFilter function is referentially stable and the map(Chips) is cached using getFilter as a cache key. This however breaks because the function is using get() to retrieve up to date data from the zustand store. So even though the reference to the function remains the same the underlying data might have changed.

I'm not sure what a good solution would look like. I was thinking that one should be able to mark certain functions as not memoizable.

Currently I can only opt-out the entire file and when someone else uses useFilterSettings somewhere else they would be surprised.

Thanks

How often does this bug happen?

Every time

What version of React are you using?

19.1.0

What version of React Compiler are you using?

19.1.0-rc.2

MarkusWendorf avatar May 18 '25 16:05 MarkusWendorf

Thanks for posting! As a quick reaction it looks like zustand is breaking the rules of React, specifically it’s mutating values internally rather than create a new “immutable” value.

We’ll have to investigate a bit more and see what we can do to help users detect this, it’s certainly not great to have code that was working break.

josephsavona avatar May 18 '25 18:05 josephsavona

Zustand using the temporal plugin also breaks

const { futureStates, pastStates, undo, redo, clear } = useTemporalStore.temporal.getState();

futureStates & pastStates no longer trigger re-renders

we're using 'use no memo' to escape out of the compiler on these files

adamistheanswer avatar May 28 '25 11:05 adamistheanswer

Zustand store also breaks when using Auto Generating Selectors

const someProp = useStore.use.someProp()

ltlaitoff avatar Aug 05 '25 14:08 ltlaitoff