realm-js icon indicating copy to clipboard operation
realm-js copied to clipboard

Allow usage of realm outside of react components

Open Fuzzyma opened this issue 2 years ago • 11 comments

Problem

When using @realm/react, it provides you with a ... Provider. And in child components you can use hooks to get access to your realm. However, I want to be able to access the realm in other parts of the application that are decoupled from the react components. I dont see a way how to do that since the realm created in the provider is always closed access

Solution

Allow to pass in a realm to the Provider that is used instead of the automatically created one. This realm can then be used for functionality outside of react

Alternatives

Atm, I pass in a custom object to the realmRef prop that is filled with the realm and share that custom object to other parts of my application:

export const realmRef: { current: Realm | null } = { current: null }

// later
<RealmProvider realmRef={realmRef} />

However, this leads to problems with hot reloading and is really hacky

How important is this improvement for you?

I would like to have it but have a workaround

Feature would mainly be used with

Local Database only

// Edit: I found this comment for realmRef in your code:

  /**
   * A ref to the Realm instance. This is useful if you need to access the Realm
   * instance outside of a component that uses the Realm hooks.
   */

So, it seems like I am using realmRef correctly - kinda. Because you cannot use useRef outside of react components to create a ref (i faked it). Also: Hot reloading breaks. If i have to guess its because a new realm is created on rerender and the old one is still around somehow

Fuzzyma avatar Nov 21 '23 22:11 Fuzzyma

So I ended up copying a bunch of implementation files to still have access to hooks but use a global realm instance instead of an internal one. That works but ofc is super hacky

Fuzzyma avatar Nov 22 '23 09:11 Fuzzyma

@Fuzzyma Thank you for the suggestion. We have a future project to refcount Realm instances, and I think it will be natural to return to your suggestion once we start on that project.

kneth avatar Dec 01 '23 15:12 kneth

@Fuzzyma

So I ended up copying a bunch of implementation files to still have access to hooks but use a global realm instance instead of an internal one. That works but ofc is super hacky

So, I'm on a project and started to implement realm on it as well, but not all things on the app is "offline first" and does not use realm, because of that we use a pretty based "services architecture" (just remove all service logic from components). I'm really curious about how you did manage to use like that, maybe it can enable my team to work with realms but still use it only on services layers, can you show a little on how you managed to do that ?

Also, I'am worried about the "sync" part, seeing examples like using an query for list and from nowhere it updates because of syncing, maybe calling a function that only get the response of a query doe's not carry the sync part and does not update until a forced refetch ? Have you seen something about that ?

AlecsFarias avatar Dec 12 '23 23:12 AlecsFarias

I have a file where I create a new realm and export that one. I copied over createUseObject to use the global realm instead. Then I exported my own useRealm method that just return the global realm. I also create my own useQuery and useObject

export const useRealm = getRealm;
export const useQuery = createUseQuery(getRealm);
export const useObject = createUseObject(getRealm);

In the react world i make sure to only import from my file and never from react realm. All updates still work and its updating my views as expected. Its not really a suprise since I just replaced the realm (which is recreated whenever react rerenders) with a stable one

Fuzzyma avatar Dec 13 '23 09:12 Fuzzyma

@Fuzzyma Can you please share how you create a new realm?

I am new on this and trying to achieve a similar thing. I need to use the db outside of react components so I need to replace the below.

const realmConfig: Realm.Configuration = {
  schema: [Test],
  schemaVersion: 1,
};

export const {RealmProvider, useRealm, useObject, useQuery} =
  createRealmContext(realmConfig);

kscgl avatar Dec 22 '23 05:12 kscgl

@kscgl I am actually experimenting again with just using useEffect in a component to save the useRealm into an outside var.

const realm = useRealm()
useEffect(() => {
  globalRealm = realm 
  // or some global func:
  setGlobalRealm(realm)
}, [realm])

When I tested this in the past, it crashed on me since realm objects were in use that were invalid but for that case you have to convert them to plain objects (I think that was the issue. still investigating)

However, that makes it exceptionally harder to use syncing because for syncing you need users and those are supplied via the user context and now you have to hack a few more files. I dont wanna do that so I try to go with the above solution.

As for what I did: I tried to explain it before. It involved copying the source code for useRealm and createUseObject and use my own realm instead of creating one there.

A realm can be created by just calling new Realm(config)

Fuzzyma avatar Dec 22 '23 09:12 Fuzzyma

@Fuzzyma I see. thanks for the explanation. I wasn't sure if you were talking about new Realm() or something else. It seems like I have to go with new Realm() and creating Services to be used everywhere and lose 'hooks' priviliges.

kscgl avatar Dec 22 '23 20:12 kscgl

@Fuzzyma Just wanted to provide some information if you are trying to use realm outside of RealmProvider.

First off, if you invoke Realm.open() with the same configuration you have passed into RealmProvider, then you will receive a shared instance of realm. Although be careful, if one of these shared instances are closed with realm.close(), then all of them will close.

Second, there is a property on RealmProvider called closeOnUnmount. Set this to false to ensure that your shared instance of realm is not closed when the RealmProvider is closed (if that's important to you).

That should provide enough flexibility to do whatever it is you need. Let me know if that helps!

takameyer avatar Dec 25 '23 14:12 takameyer

@takameyer What if I call new Realm(configuration) first to create the realm instance and pass the same configuration to the createRealmContext(configuration), will I receive the same shared instance within the components that use the provider from createRealmContext?

susonthapa avatar May 06 '24 08:05 susonthapa

you can create new realm instance by using realm create with same config you used to create realmprovider realm js

nikhil2882 avatar Jun 05 '24 07:06 nikhil2882