immerjs / use-immer

Use immer to drive state with a React hooks
MIT License
4.04k stars 92 forks source link

`source is undefined` when calling a nested mutation in a custom hook from a library when using immer 9.0.13+ #102

Closed MikeRippon closed 1 year ago

MikeRippon commented 2 years ago

I think this one might be a bit obscure, and there's a few workarounds, but it appears to be a newly introduced bug so thought it might be important to record it for you guys in case any related issues crop up. Not sure if it should be in this repo or the core immer repo, but I can only recreate it with use-immer. My real-world case is a lot more complex than this, but I've tried to get the example as simple as possible.

// Firefox
Uncaught TypeError: source is undefined
    peek proxy.ts:238
    set proxy.ts:146
    node_modules bundle.js:380
    produce immerClass.ts:94
    ...

// Chrome
Uncaught TypeError: Cannot read properties of undefined (reading 'age')
    at peek (proxy.ts:238:1)
    at Object.set (proxy.ts:146:1)
    at index.ts:44:1
    at Immer.produce (immerClass.ts:94:1)
    ...

I've added a few more test cases in there that don't cause the exception. They match the labels of the buttons in the app, in approximate order of weirdness:

  1. Use useState instead of useImmer, and make nested calls to produce in library - ✓ works
  2. Using the same useImmer instance that has the bug...
    • 2b Expose the mutation method and perform the mutation in the app codebase instead of the library - ✓ works
    • 2c No nested call to produce, increment the age by mutating the first draft in the library - ✓ works
  3. Same as 1, but also freeze the initial state so it's basically a carbon copy of the actual code from useImmer - ✓ works
  4. Nested mutation, absolutely identical to 2, which causes the bug. but the useImmer & mutation code is in the app component instead of the library - ✓ works
  5. (no example) Downgrade immer from 9.0.13 to 9.0.12, despite 9.0.13 looking like it just changed a type definition and some documentation - ✓ works

I don't really understand the internals of immer, but it looked like some sort of global state wasn't being handled properly, so I converted everything in the library to a peer dependency just to make sure there weren't two versions of anything, but this didn't have any effect.

Edit: I'm using use-immer 0.7.0, which is odd, because the package.json and release history in GH suggest the latest is 0.6.1... I'm having a very weird week.

mweststrate commented 1 year ago

Closing as I don't have a better idea to what to do with this issue :)