I need to persist lots of different data objects (nested, with relationships) that are used across several components with Realm (10.1.3) for a react native project (0.63.3).
My goal is to have a class that provides an API with read and write operations on Realm for all other modules, screens and so on. However I have trouble finding the right pattern for it.
Idea 1: Implement all operations in one place, open and close Realms each time
Write-Operations run smoothly:
export class RealmProviderSample { static asnyc writeObject(object:ObjectType) { const realm = await Realm.open(config); realm.write(() => { realm.create("ObjectType", object); }); realm.close(); } // ...}
However reading an object and closing the realm leads to Errors as the data cannot be used anymore when the realm is closed. I got stuck on trying to clone the realm object (I need a deep copy), but the clone is always empty. This seems to be a known problem: issue 2805, issue 1074
import { cloneDeep } from 'lodash';export class RealmProviderSample { // ... static async readObject() : Promise<Object> { let object:Object = {} const realm = await Realm.open(config) const tmpReferencedObject = <Object> realm.objects("Object") object = cloneDeep(tmpReferencedObject) console.log(object) // object is empty {} realm.close(); return tmpReferencedObject // Error "invalidated results" when using the returned object, because realm was closed } }
This approach only works when the copy problem is solved (there is a solution for Swift. Encode in JSON and then Decode back is not working either, because the Realm object has relations (TypeError JSON.stringify cannot serialize cyclic structures)
Idea 2: Implement all operations in one place, manage a global realm instance
An alternative solution would be to have a global realm instance that is opened on the first use and closed, when the application is send to the background.
var realm:Realmexport class RealmProviderSample { static asnyc writeObject(object:ObjectType) { if (!realm || realm.isClosed) { realm = await Realm.open(config); } realm.write(() => { realm.create("ObjectType", object); }); } static async readObject() : Promise<Object> { if (!realm || realm.isClosed) { realm = await Realm.open(config); } return <Object> realm.objects("Object") } // call this when application goes to background? static closeRealmIfOpen(){ if (realm && !realm.isClosed) { realm.close(); } }}
To me it is not clear whether it is a good idea to leave the realm open. In the docs it is stated that a realm should always be closed when not used.
Idea 3: Implement each operation where it is used, manage each realm separately
This the approach I can see in all the tutorials, but I have the feeling that it doesn't scale. Also most samples don't close the realms.
class MyScreen extends React.Component { realm: Realm; // constructor... componentDidMount() { this.realm = new Realm(config); this.realm.write(() => { this.realm.create("ObjectType", object); }); } componentWillUnmount() { this.realm.close() } // render ...}
If data is used across several screens and components (some sub-data passed via Props) it might be difficult to close the instance safely.
I prefer idea one - but it doesn't work without the deep copy of a realm object. Did anyone solve this problem? Which pattern do you use and does it scale?