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

Better Multi React DOM support #6233

Open
aight8 opened this issue Nov 4, 2023 · 5 comments
Open

Better Multi React DOM support #6233

aight8 opened this issue Nov 4, 2023 · 5 comments

Comments

@aight8
Copy link

aight8 commented Nov 4, 2023

Problem

I use react-native-navigation, which uses many React DOM's (every Screen is a separate DOM)
Every screen shares a common Wrapper, which initializes Realm, App and optionally the User Context.
The problem is that:

  1. AppProvider and RealmProvider creates and configure a fresh instance of Realm.App and Realm object for the DOM. I just want to initialize and reuse the global realm and realm.app object externally. Also the observing doesn't work like this, I don't know exactly why, but I think that the global realm and realm.app object only corresponds to the last changed screen.
  2. I have tried to simply set Realm and Realm.App through the Context.Provider but they are not exported. Also, the AppProvider contains some extra logic (also renders AuthOperationProvider).
<AppProvider
	appRef={appRef}
	id={'XXXXX'}
>
	<ConditionalWrap
		condition={userRequired}
		wrap={(children) => (
			<UserProvider fallback={<Text>UserProvider fallback</Text>}>
				{children}
			</UserProvider>
		)}
	>
		<RealmProvider
			realmRef={realmRef}
			closeOnUnmount={false}
			deleteRealmIfMigrationNeeded={true}
			schema={[Model]}
		>
			{children}
		</RealmProvider>
	</ConditionalWrap>
</AppProvider>

Solution

const realmApp = new Realm.App({})
const realm = new Realm({})

// Here I can setup the single instance:

realmApp.addEventListener(() => {
    // something
})
realmApp.currentUser?.addEventListener(() => {
    // change Screen (e.g. login screen)
})
<AppProvider
	...
	appInstance={realmApp}
	...
>
	<ConditionalWrap
		condition={userRequired}
		wrap={(children) => (
			<UserProvider fallback={<Text>UserProvider fallback</Text>}>
				{children}
			</UserProvider>
		)}
	>
		<RealmProvider
			...
			realmInstance={realm} // explicitly also closeOnUnmount
			...
		>
			{children}
		</RealmProvider>
	</ConditionalWrap>
</AppProvider>

As result the Realm and Realm.App Object is managed externally and as side effect the code React DOM stays little bit cleaner.

Alternatives

There is no real alternatives. I currently forked realm-js, exported the React Context.Provider, manually add AuthOperationProvider etc.

How important is this improvement for you?

Dealbreaker

Feature would mainly be used with

Atlas Device Sync

@kneth
Copy link
Member

kneth commented Nov 8, 2023

@aight8 Thank you raising the issue. We don't have a quick fix but we use React Native Navigation on one of our examples. I will bring it up with the team to get some ideas.

@aight8
Copy link
Author

aight8 commented Nov 8, 2023

Hi thank you. I made it work by a fork and export createUseObject, createUseQuery, createUseRealm from '@realm/react' etc. (don't know if the list is complete).

Just for clearification of the problem (that we understand each other correctly), the examples uses react-navigation (single React DOM based), I use react-native-navigation (many React DOM based)

In the example it's like:

- AppProvider (App.tsx)
   - UserProvider (otherwise show Login component)
      - RealmProvider (AuthenticatedApp.tsx)
         - ... the whole app incl. navigation... 

A react-native-navigation based app is it like:

// HomeScreen
- AppProvider
   - UserProvider
      - RealmProvider

// SettingsScreen
- AppProvider
   - UserProvider
      - RealmProvider

// Tab1ContentScreen
- AppProvider
   - UserProvider
      - RealmProvider

// Overlay1Screen
- AppProvider
   - UserProvider
      - RealmProvider

// Modal1Screen
- AppProvider
   - UserProvider
      - RealmProvider

// TopBarHeaderScreen
- AppProvider
   - UserProvider
      - RealmProvider

// etc.

So think about, every Root View, Overlay/Modals are total separately rendered React DOM's.
Some of the screens are rendered and visible at the same time. (e.g. simultaneously: Tab1ContentScreen, Top1ContentTopBarScreen, Modal1Screen)

This has the following consequences:

  • A realm can only be opened by one screen at a time anyway
  • And also if multiple connections were possible: AppProvider and RealmProvider creates Realm and Realm.App objects. It is sufficient to create them once, or is even desired to keep them synchronized (the events are also triggered separately everywhere)

Motivation

The easiest way to solve this issue, to let the user provide Realm and Realm.App object.

@nicolaosm
Copy link

Would love to see a solution for this.

@kraenhansen
Copy link
Member

@aight8 and @nicolaosm - wanted to mention that we're also tracking this issue for a similar feature that you might want to 👍 and watch: #6283

@gagik
Copy link
Contributor

gagik commented Jun 18, 2024

@aight8 @nicolaosm

Realm React v0.8.0 now supports using an existing Realm instance with a RealmProvider or createRealmContext!
Should provide a nice solution to this usecase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants