That’s somewhat similar to the solutions I created in Swift. The first approach is as I described earlier. The second approach involves using a local Realm without requiring sign-in initially, then transitioning to Realm Sync once the user signs in. Both of these solutions are functional and have been tested. I’ve sanitized the examples, so if there are any discrepancies, please let me know. However, these should provide a good direction to follow.
Here are the Swift solutions I got in my repos it would need to be translated to JavaScript (React) specifically like I did above for the imports you want to have.
But this is the direction that would help you out, and yes I have tested this in a demo app. It does work just fine on an M3 Pro Mac mini.
Keep in mind, this is written in Swift, and you’d have to translate the React Equivalent but Swift is pretty easy to read for the direction it’s going as a solution for what you should try to do.
import SwiftUI
import RealmSwift
// Define your App ID
let appId = "your-app-id"
let app = App(id: appId)
// Your Realm context provider setup
let realmConfig: Realm.Configuration = {
let user = app.currentUser!
var config = user.flexibleSyncConfiguration(initialSubscriptions: { subs in
// Set up your initial subscriptions here
})
config.objectTypes = [YourObjectType.self] // Replace with your object types
return config
}()
// Your login view
struct LoginView: View {
@State private var email: String = ""
@State private var password: String = ""
@State private var isLoggingIn = false
var body: some View {
VStack {
TextField("Email", text: $email)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
SecureField("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
if isLoggingIn {
ProgressView()
} else {
Button("Log In") {
isLoggingIn = true
app.login(credentials: .emailPassword(email: email, password: password)) { result in
switch result {
case .success(let user):
print("Successfully logged in as user: \(user)")
// Here the user is logged in, and we can now initialize the Realm
NotificationCenter.default.post(name: NSNotification.Name("UserDidLogin"), object: nil)
case .failure(let error):
print("Failed to log in: \(error.localizedDescription)")
}
isLoggingIn = false
}
}
}
}
.padding()
}
}
// Your main app view
struct ContentView: View {
@State private var isLoggedIn = false
var body: some View {
if isLoggedIn {
SyncRealmView()
} else {
LoginView()
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("UserDidLogin"))) { _ in
self.isLoggedIn = true
}
}
}
}
// The view where you use the synced Realm
struct SyncRealmView: View {
@ObservedResults(YourObjectType.self, configuration: realmConfig) var objects
var body: some View {
List(objects) { object in
Text("\(object.name)")
}
}
}
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
To explain what it’s doing:
- The
LoginView
handles user authentication. Once the user successfully logs in, a notification (UserDidLogin
) is posted.
- The
ContentView
listens for the UserDidLogin
notification. Once the notification is received, it updates the state to show the SyncRealmView
that uses the synced Realm instance.
- The
realmConfig
is defined based on the current user. It’s set up after the user has logged in, ensuring that the Realm can be opened with a valid user.
Now, there is ANOTHER way to do this, and this is the two Realms method I mentioned, I don’t have examples in JavaScript, but I do have working examples of this in Swift already I’ve sanitized.
import SwiftUI
import RealmSwift
// Define your App ID
let appId = "your-app-id"
let app = App(id: appId)
// Local Realm configuration (Unauthenticated state)
let localConfig = Realm.Configuration(inMemoryIdentifier: "localRealm")
// Synced Realm configuration (Authenticated state)
func syncedRealmConfig(for user: User) -> Realm.Configuration {
var config = user.flexibleSyncConfiguration(initialSubscriptions: { subs in
// Set up your initial subscriptions here
})
config.objectTypes = [YourObjectType.self] // Replace with your object types
return config
}
// Your login view
struct LoginView: View {
@State private var email: String = ""
@State private var password: String = ""
@State private var isLoggingIn = false
var body: some View {
VStack {
TextField("Email", text: $email)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
SecureField("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
if isLoggingIn {
ProgressView()
} else {
Button("Log In") {
isLoggingIn = true
app.login(credentials: .emailPassword(email: email, password: password)) { result in
switch result {
case .success(let user):
print("Successfully logged in as user: \(user)")
// Switch to synced Realm after login
NotificationCenter.default.post(name: NSNotification.Name("UserDidLogin"), object: user)
case .failure(let error):
print("Failed to log in: \(error.localizedDescription)")
}
isLoggingIn = false
}
}
}
}
.padding()
}
}
// Your main app view
struct ContentView: View {
@State private var realmConfig: Realm.Configuration = localConfig
@State private var isLoggedIn = false
var body: some View {
if isLoggedIn {
SyncedRealmView(realmConfig: realmConfig)
} else {
LocalRealmView(realmConfig: realmConfig)
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("UserDidLogin"))) { notification in
if let user = notification.object as? User {
// Switch to synced Realm configuration
self.realmConfig = syncedRealmConfig(for: user)
self.isLoggedIn = true
}
}
}
}
}
// View using the local Realm
struct LocalRealmView: View {
let realmConfig: Realm.Configuration
var body: some View {
// Replace `YourLocalObjectType` with your local Realm object type
@ObservedResults(YourLocalObjectType.self, configuration: realmConfig) var objects
List(objects) { object in
Text("\(object.name)")
}
}
}
// View using the synced Realm
struct SyncedRealmView: View {
let realmConfig: Realm.Configuration
var body: some View {
// Replace `YourObjectType` with your synced Realm object type
@ObservedResults(YourObjectType.self, configuration: realmConfig) var objects
List(objects) { object in
Text("\(object.name)")
}
}
}
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
What it’s doing:
- We have a LOCAL Realm that’s used to access local data without login.
- Synced Realm after logging in.
To better clarify:
You make the app start with a local in memory Realm configuration (localConfig
) when the user is not logged in. Then you manage the local only data while the user is unauthenticated.
Once the user logs in, the app switches to a synced Realm configuration. This is done by listening for a login notification (UserDidLogin
) and updating the realmConfig
in ContentView
to point to the synced Realm.
Keep in mind LocalRealmView
and SyncedRealmView
are two different views that each use their respective Realm configurations. LocalRealmView
uses the local Realm, and SyncedRealmView
uses the synced Realm after login.
You have to make sure the app listens for a notification that the user has logged in. Once this happens it updates the state to use the synced Realm configuration.
This is probably more so the direction you’re wanting to go for, but both of these solutions work for what you’re wanting to do. But the better route is to have it wait until after logging in.