realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.79k stars 575 forks source link

Upgrading @realm/react from 0.7.0 to 0.8.0+ breaks app #6842

Closed nzapponi closed 2 months ago

nzapponi commented 2 months ago

How frequently does the bug occur?

Always

Description

Unable to keep the app running, the realm keeps getting closed for no reason

Stacktrace & log output

Error: Cannot access realm that has been closed.

Can you reproduce the bug?

Always

Reproduction Steps

This is how the provider is initialized:

import { RealmProvider as Provider } from "@realm/react";
import { Buffer } from "buffer";
import { PropsWithChildren, useContext } from "react";
import Spinner from "../components/Spinner";
import { schemas } from "../lib/store/db/realm";
import { EncryptionKeyContext } from "./SessionProvider";

export default function RealmProvider({ children }: PropsWithChildren) {
  const encryptionKeys = useContext(EncryptionKeyContext);

  if (!encryptionKeys.realmKey) {
    return <Spinner />;
  }

  return (
    <Provider
      schema={schemas}
      schemaVersion={5}
      encryptionKey={Buffer.from(encryptionKeys.realmKey, "base64")}
    >
      {children}
    </Provider>
  );
}

This provider only mounts once, so it shouldn't ever close.

Version

0.8.0+

What services are you using?

Local Database only

Are you using encryption?

Yes

Platform OS and version(s)

iPhone 15, OS 17.5

Build environment

Expo 51.0.26 Realm 12.12.1

Cocoapods version

No response

sync-by-unito[bot] commented 2 months ago

➤ PM Bot commented:

Jira ticket: RJS-2887

kneth commented 2 months ago

Try to set closeOnUnmount to false (https://www.mongodb.com/docs/atlas/device-sdks/sdk/react-native/api-reference/realm-provider/)

nzapponi commented 2 months ago

Ok so I tried to set closeOnMount to false and, whilst the app no longer crashes, it's still acting very weird. Basically, it seems like RealmProvider re-renders all of its children after any action.

The app loads correctly, but the moment I press on anything, every child of RealmProvider gets re-rendered and, in my case, expo-router resets the whole app to the entry point.

There's nothing appearing in the logs when that occurs.

RemiHin commented 2 months ago

Having the same issue, upgrading from 0.7.0 to anything higher makes my app rerender continuously.

skoob13 commented 2 months ago

I am having the same issue. 0.7.0 works well, but all other versions are broken.

Reproduction:

export default function Layout() {
  return (
    <RealmProvider schema={schema} closeOnUnmount={false}>
      <TextInput />
    </RealmProvider>
  );
}

Focusing the text input will always re-render the children of RealmProvider on Android, so the keyboard always hides.

kraenhansen commented 2 months ago

I tried to setup a project to debug, but I've failed to reproduce it consistently. Would any of you be able to share a link to a repository which has this symptom? As minimal as possible to trigger the issue and instructions on the steps I'd have to take 🙏

kraenhansen commented 2 months ago

Never mind - I got a reliable reproduction and fixed the issue. Look out for an upcoming release 👍 Thanks a lot for reporting this @nzapponi and for your patience 💙 @RemiHin & @skoob13!

nzapponi commented 2 months ago

Awesome thanks for the support!!

kraenhansen commented 2 months ago

The fix is released as @realm/react@0.10.1 - please take it for a spin and report back 🤞

nzapponi commented 2 months ago

Yeah, issue resolved. Thanks!

reason-alex commented 1 month ago

So what are the best practices now for using @realm/react with expo-router and other react navigation libraries that have, to my understanding, separate DOM trees per screen? Do we need to wrap each screen in a Realm Provider? Or can we have just one top level RealmProvider in our _layout file? Or does that need closeOnUnmount set to false?

nzapponi commented 1 month ago

FWIW I kept my original code structure, with a single provider in my app layout, and it just works.

With the update I didn't have to set closeOnMount: false, since in any case my provider never unmounts.

Not sure if that's the recommended best practice though!