-
-
Notifications
You must be signed in to change notification settings - Fork 265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
defineProperty trap makes property non-CEW in React Native (Hermes engine) #765
Comments
I suggest two options:
But I'm hesitant for option 2 because the only workaround I can come up with is convoluted and brittle.We already know that the // Inside proxyFunction()
let isExecutingProxySetTrap = false
const proxy = new Proxy(target, {
set: (target, prop, value, receiver) => {
isExecutingProxySetTrap = true
try {
// Actual set trap logic goes here
return Reflect.set(target, prop, value, receiver)
} finally {
isExecutingProxySetTrap = false
}
},
defineProperty: (target, prop, desc) => {
if (isExecutingProxySetTrap) {
// If the defineProperty trap is triggered while processing the set trap,
// then we know that 'desc' must have 'value' prop and nothing else
// according to the ECMAScript spec.
// So we can strip all other properties (erroneously added by Hermes)
desc = { value: desc.value }
}
// Actual defineProperty trap logic goes here
return Reflect.defineProperty(target, prop, desc)
},
}) Admittedly this is convoluted. It's also not foolproof; it might fail if the set trap invokes another set trap. In which case we'd need to use a counter instead of a boolean flag. But there may still be other pitfalls with this trick. Not to mention degrading performance. For now, I suggest we wait for confirmation from another person that 1.11.0 is indeed the culprit. Then we can revert #760. |
I make some tests and found something interesting. import { Text, View } from 'react-native'
import React from 'react'
import { proxy, snapshot, useSnapshot } from 'valtio'
const store = proxy({
foo: {
1: 22,
},
})
export default function App() {
const { foo } = useSnapshot(store)
const fooContent = JSON.stringify(foo, null, 2)
return (
<View style={{ flex: 1, marginVertical: 100 }}>
<Text>foo: {fooContent}</Text>
</View>
)
} If I change If I change |
This issue is still present in latest RN + latest valtio using the steps in #765 (comment) @pastelmind how did you resolve the issue? |
@sharathprabhal I do not use React Native, so unfortunately I cannot verify right now that the issue has been fixed. However, Valtio 1.11.1+ is supposed to be OK for RN. Could you specify the exact version of Hermes/RN and Valtio, rather than "latest"? A reproduction repository would also help. |
@pastelmind Thanks for the response! The versions are
The repro repo is at https://github.com/sharathprabhal/valtio-765-repro/blob/main/App.tsx#L34 . Its a brand new RN app with the basic valtio store. Thanks in advance! |
I also had the same problem today: import { proxy, useSnapshot } from "valtio";
export interface FilterState {
brands: string[];
gender: string[];
}
const state = proxy<FilterState>({
brands: [],
gender: []
});
export default function useFilter() {
const snap = useSnapshot(state);
return {
...snap,
toggleBrand(brand: string) {
if (state.brands.includes(brand)) {
state.brands = [...state.brands.filter(b => b !== brand)];
}
else {
state.brands = [...state.brands, brand];
}
}
}
} Error when I using
RN: |
@pastelmind Are you around? @sharathprabhal Maybe you want to open a new issue with the reproduction. |
I'm not available at the moment. Hopefully I'll be able to dig into this before the weekend. |
I was able to work around the issue by disabling Hermes. All set for now. |
|
Summary
This issue describes the bug reported in #752 (comment) and #764. In both cases, Valtio was added to a React Native project with the Hermes engine enabled. Assigning a new value to a property on a proxy store object marked the property as non-configurable and non-writable, effectively "freezing" the property and preventing future mutations.
The source of the bug was initially attributed to #752. However, I suspect that the actual cause is #760. My own investigations (#764 (reply in thread) and #764 (reply in thread)) indicate that the bug occurs on 1.11.0 (with #760), but not on 1.10.7 (with #752) or 1.10.6. Also, the bug affects proxy objects (affected by #760) rather than their snapshots (affected by #752).
The root cause appears to be a bug in the Proxy implementation of Hermes. I opened a bug report (facebook/hermes#1065) and am waiting for confirmation from the Hermes devs.
Meanwhile, it would be nice if we handled this ourselves. Hermes and React Native are large projects and move slower than the rest of the JS ecosystem. Even if Hermes fixes the problem immediately (if at all), it would take a long time for the fix to propagate to downstream projects. Many people are using React Native today and we need to support them too.
Link to reproduction
See following discussion comments
Check List
Please do not ask questions in issues.
Please include a minimal reproduction.
The text was updated successfully, but these errors were encountered: