Closed meluskyc closed 1 year ago
Thanks for reporting. Out of curiosity, does it work for a simple case with immer?
Yeah, this simple test succeeds, strangely. The complex case also succeeds in proxy-memoize 1.2.0, but 2.0.0 seems to break it.
import { memoize } from "proxy-memoize";
import { produce } from "immer";
import { describe, it, expect } from "@jest/globals";
describe("selectors w/ immer", () => {
it("works", () => {
let state = Object.freeze({
x: {
y: {
z: [{ m: 3 }],
},
},
q: {
n: {
mm: 21,
},
},
});
const selectorOne = memoize((s: typeof state) => {
return s.x.y.z[0];
});
expect(selectorOne(state)).toEqual({ m: 3 });
state = produce(state, (draft) => {
draft.x.y = { z: [] };
});
// succeeds
expect(selectorOne(state)).toEqual(undefined);
});
});
Interesting. Would you be able to dig more into it?
The difference between v1.2.0 and v2.0.0 can be in proxy-compare
.
Oops, scratch that. 2.0.3 works fine for this test and 2.0.4 seems to break it.
I'll try to look into it some more.
I am having the same problem. Using immer + zustand + this library. Very inconvenient problem 😢 ...
Seems for me like immer returning objects with changed config for them... Bcs in my case immer and proxy-memoize are not used at the same time, but when using immer he returns some object to zustand store and after that object is passed to proxy-memoize memoized function I have this error... but I will investigate more, very annoying problem...
⚠️ If auto freezing is enabled, recipes are not entirely side-effect free: Any plain object or array that ends up in the produced result, will be frozen, even when these objects were not frozen before the start of the producer! ⚠️
This solves the issue:
import { setAutoFreeze } from "immer";
setAutoFreeze(false);
@valerii15298 Note that disabling immer's auto freeze will likely result in reduced performance. https://github.com/immerjs/immer/issues/687
To recap, the issue seems to be immer's auto-freeze combined with the target cache from 220bffe returning the non-frozen proxy.
This is unfortunate since freezing helps prevent accidental state mutations. But I don't see another workaround outside of reverting 220bffe...
@dai-shi
Recursive proxying frozen objects doesn't simply work. It's JS restriction:
$ node
Welcome to Node.js v18.14.0.
Type ".help" for more information.
> obj = { nested: {} }
{ nested: {} }
> Object.freeze(obj.nested)
{}
> Object.freeze(obj)
{ nested: {} }
> p = new Proxy(obj, {
... get(target, prop) { return new Proxy(target[prop], {}) }
... })
Proxy [ { nested: {} }, { get: [Function: get] } ]
> p.nested
Uncaught:
TypeError: 'get' on proxy: property 'nested' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '#<Object>' but got '#<Object>')
OK, it sounds like we should update the documentation to recommend disabling auto-freeze with immer. Would you like a PR for that?
It is strange since I would expect immer is also using nested proxies with frozen objects, but maybe that's not the case...
Would you like a PR for that?
Yes, please.
Hi,
I'm running into an issue when using nested selectors with immer. The test below fails for me.
https://codesandbox.io/s/youthful-grass-14m8cp?file=/src/index.test.js
TypeError: 'get' on proxy: property 'n' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '#<Object>' but got '#<Object>')
Any ideas? Thanks!