-
Notifications
You must be signed in to change notification settings - Fork 561
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
Incorrect wrapping of proxy objects on every render #4513
Comments
@mfbx9da4 Good catch. Really appreciate the feedback. We will investigate this as time allows and get back to you when we have something in review. |
@mfbx9da4 We have a good idea for fixing the proxy wrapper. That being said, can you please make a separate issue for:
We would also appreciate an example where this is not being handled correctly 🙂 Thanks so much for your feedback! |
@takameyer what do you make of my singleton object proposal? Is there somewhere better to discuss that? |
@mfbx9da4 I think it's worth looking into. We have discussed various ways we could improve or notification systems. I think making a feature request would be a good way to invoke more discussion. |
Is there any progress on this? In my app, I do a CPU-intensive operation using the data stored in the database. I tried the following: const result = useMemo(() => {
console.log('starting CPU intensive operation');
return intensiveOperation(object);
}, [object]); but it seems like this if fired every time the component state changes, not when the realm "object" dependency changes. Is it what's described in this ticket? |
It looks like the same thing that is described @maxencehenneron, yes. There's a PR #4519 with a fix for this issue which we are reviewing right now. |
Hi, I noticed that Is there a previous version where this works correctly? The README file caught my attention:
const Component = () => {
// ObjectClass is a class extending Realm.Object, which should have been provided in the Realm Config.
// It is also possible to use the model's name as a string ( ex. "Object" ) if you are not using class based models.
const collection = useQuery(ObjectClass);
// The methods `sorted` and `filtered` should be wrapped in a useMemo.
const sortedCollection = useMemo(() => collection.sorted(), [collection]);
return (
<FlatList data={sortedCollection} renderItem={({ item }) => <Object item={item}/>
)
} That is not working as expected, all items in my list are being re-rendered. |
As a workaround, I've implemented a caching hook on top of the ones provided by @realm/react: export const createRefCache = object => {
return new Proxy(
{},
{
get: function (target, property) {
return object[property];
},
set: function (target, property, value) {
object[property] = value;
},
},
);
};
export const useCachedObject = (object, otherDeps = []) => {
const [counter, setCounter] = useState(0);
const forceRender = () => setCounter(n => n + 1);
// eslint-disable-next-line react-hooks/exhaustive-deps
const memoObject = useMemo(() => createRefCache(object), [counter, ...otherDeps]);
useEffect(() => {
const listener = (obj, changes) => {
if (changes.deletions.length || changes.insertions.length || changes.modifications.length) {
forceRender();
}
};
memoObject.addListener(listener);
return () => {
memoObject.removeListener(listener);
};
}, [memoObject]);
return memoObject;
}; Let me hear what you think about it! |
This has been fixed in |
@takameyer
|
I still experience issue for both useQuery and useObject |
Argh, same. Just stumbled upon this issue after creating #5264 . |
How frequently does the bug occur?
All the time
Description
https://github.com/realm/realm-js/blob/master/packages/realm-react/src/useObject.tsx#L78 @takameyer
The intention of this code is that the reference will only change if the object has changed to play nicely with React's immutability conventions. However, the hook is not invoked only when the hook fires. It is invoked anytime the parent component renders. The component could be rendering because of a totally unrelated change to some other component state which will cause unnecessary Proxy wrapping, unnecessarily new references, break React's immutability conventions and contradicts the intention of this code.
Easier to explain with code
https://codesandbox.io/s/modern-field-7ety98?file=/src/App.js:69-642
The fix here is to create the new proxy in the updateCallback.
I think a further improvement would be to have a singleton observable object with a single realm listener with a reference count referring to the number of active hooks using it. This would:
useObject
in two different components will return the same reference and so works best with React's immutability tendencies.Side issue: while the object cache and collection will make great strides to improving immutability, non-primitive values such as Dates, sets and dictionaries will not be immutably cached correctly. Are you aware of that?
Stacktrace & log output
No response
Can you reproduce the bug?
Yes, always
Reproduction Steps
No response
Version
main
What SDK flavour are you using?
Local Database only
Are you using encryption?
No, not using encryption
Platform OS and version(s)
ios
Build environment
Which debugger for React Native: ..
Cocoapods version
No response
The text was updated successfully, but these errors were encountered: