Skip to content
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

BUG - useQuery() does NOT return a stable reference, so a filter or sort in a useMemo is performed EVERY render #5264

Closed
channeladam opened this issue Jan 15, 2023 · 13 comments · Fixed by #5269
Assignees

Comments

@channeladam
Copy link

channeladam commented Jan 15, 2023

How frequently does the bug occur?

Always

Description

Expected useQuery to return a stable reference so any filtered() or sorted() done in a useMemo() would not be performed on every re-render.

Stacktrace & log output

No response

Can you reproduce the bug?

Always

Reproduction Steps

Create the TypeScript example as per the doco:
npx react-native init AwesomeRealmProject --template @realm/react-native-template-ts

Tweak the TypeScript example's AppNonSync.tsx to demonstrate the issue.
The changes simply setup a timer to force a rerender every half second.
The callback in the useMemo is executed every render, even though result should not have changed.

import React, {useMemo, useRef, useState} from 'react';

import {Task} from './models/Task';
import {TaskRealmContext} from './models';
import {TaskManager} from './components/TaskManager';

const {useQuery} = TaskRealmContext;

export const AppNonSync = () => {
  const result = useQuery(Task);

  const oldResultRef = useRef(result);

  // Force a rerender every 1/2 second
  const [blah, setBlah] = useState(true);
  setTimeout(() => {
    if (oldResultRef.current !== result) {
      console.log('results are different');
    }

    oldResultRef.current = result;

    // trigger rerender
    setBlah(prev => !prev);
  }, 500);

  const tasks = useMemo(() => {
    console.log('############## sorting #############');
    return result.sorted('createdAt');
  }, [result]);

  return <TaskManager tasks={tasks} />;
};

Version

Same as template - and latest 11.3.1

What services are you using?

Local Database only

Are you using encryption?

No

Platform OS and version(s)

Android 11 R API 30 - Pixel 5 emulator

Build environment

Which debugger for React Native: ..
Flipper

Cocoapods version

No response

@channeladam
Copy link
Author

This is a pretty foundational/serious issue for me to hit... has anyone else been using Realm React, or am I the first?
I'd like to know, because I am trying to build an app in a startup and I've sunk a lot of time I don't have into trying to get Realm working for us. If Realm React isn't production ready, then I'd like to know.

@dimonnwc3
Copy link

@channeladam I have same issue and I regret starting with realm:

  • random crashes
  • hermes on iOS crash on every start in expo project
  • useQuery and useObject return new object every time when unrelated react state changes which triggers re-render
  • object deletion often randomly throws error in components, that I'm accessing invalid reference, which requires to check realmObject.isValid(), just everywhere.

@takameyer
Copy link
Contributor

@channeladam I've expanded our tests and have confirmed that this is indeed occurring. I will start working on a fix for both useQuery and useObject.

@takameyer
Copy link
Contributor

@channeladam PR is up for review. This will stablize the references for the following cases:

  • collections returned from useQuery
  • object returned from useObject
  • any collection property returned from an object

@channeladam
Copy link
Author

@takameyer wonderful, thank you! Is there a estimated timeline for the next public release of the package?

@kneth
Copy link
Contributor

kneth commented Jan 18, 2023

@channeladam Likely this week or early next week.

@takameyer
Copy link
Contributor

@channeladam @realm/react:0.4.3 has been released with the fix.

@badaz
Copy link

badaz commented Jan 26, 2023

I'm still seeing this problem in 0.4.3, this is why I stumbled on this issue actually. The only difference with the previous example is that I modify a boolean props of an item of the collection with realm.write before comparing references. This is actually what triggers the re-render of the whole component. Is thi to be expected ?

@takameyer
Copy link
Contributor

@badaz If you make a change to an item within a collection, then the collection reference will be updated. However, any other items in the collection will keep their original reference, so you should be able to create a rendering component for each item using React.Memo to only re-render when the single object reference changes.

@takameyer
Copy link
Contributor

@badaz In any case, if it's not working as you would expect, please open a new issue so we can track it and go from there.

@badaz
Copy link

badaz commented Jan 26, 2023

@badaz If you make a change to an item within a collection, then the collection reference will be updated. However, any other items in the collection will keep their original reference, so you should be able to create a rendering component for each item using React.Memo to only re-render when the single object reference changes.

Ok thanks, I'll try this

@thanhnd1o2
Copy link

@channeladam @realm/react:0.4.3 has been released with the fix.

I'm still struggling with this issue.

@thanhnd1o2
Copy link

thanhnd1o2 commented May 29, 2023

@channeladam @realm/react:0.4.3 has been released with the fix.

I'm still struggling with this issue.

I figured out that. The issue just happens when I use useQuery with filtered, filter, sorted and so on.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants