Open Realm-JS Defined in Another .JS File

2020-07-30 03:08发布

问题:

I am trying to use realm-js in react-native so what I did is created a class of realm-js in my action folder as in LoginActions.js, which will write the data after user logs in.

My Question is How do I open the same schema into another .js file?

Realm-js Defined in LoginActions.js:

class Login {
  get token() {
    return this.token;
  }
}

Login.schema = {
  name: 'Login',
  primaryKey: 'id',
  properties: {
    id: 'int',
    token: 'string',
  }
};

Then I Open the Realm to Write and Update in this Schema with Some of my functions.

Like:

// If Login User Success
Realm.open({ schema: [Login] })
.then(realm => {
  realm.write(() => {
    realm.create('Login', { id: 1, token });
  });
});

Now If want to Open this Schema into Another .js File. How will I Open it? The Main Format that I want is like in Loading.js:

import ????? from ????;

OR

Realm.open(????????)
.then(realm => {
  realm.write(() => {
    const isUser = realm.create('Login', { id: 1, token }, true);
    if(isUser.length == 1) {
        // User Logs In Directly to Main Screen
    } else {
        // Show them Login Screen
    }
  });
});

回答1:

You could save the Realm instance and use it later in the other .js file.

Without Redux (Recommended)

This is the way I recommend to use, even if you are using Redux in your app.

The schema and the realm creation happen in a realm.js file that is later imported anywhere you need in your code.

The realm.js file looks like (with 2 example schemas):

import Realm from 'realm'; 

class Favorite extends Realm.Object {}
Favorite.schema = {
  name: 'Favorite',
  primaryKey: 'id', 
  properties: {
    id:     'string', 
    type:     'string', 
    favorite: 'bool', 
    alert: 'bool', 
    tag:     'string', 
    artistId: 'int'  
  }
};

class Friend extends Realm.Object {}
Friend.schema = {
  name: 'Friend',
  primaryKey: 'fbId',
  properties: {
    name: 'string',
    fbId:'string',  
    email: 'string',
    foto: 'string',
    concerts: 'int[]',
    artists: 'int[]'
  }
};

var schemasArray = [
  Favorite, 
  Friend

export default new Realm({schema: schemasArray});

then from any component or file in your app you can simply do:

import realm from './realm'

and use it as in the realm documentation:

try {
  if(realm){
    realm.write(() => {
      //delete all objects first
      var allFavorites = realm.objects('Favorite')
      realm.delete(allFavorites)
  } catch (e) {
    console.log(`Error deleting favorites: ${schema} - ${e}`);
    reject()
  }

Redux way

If you are using Redux, you could save the realm instance to the application state first to them pass it to any component via props from the state. EDIT: At the end the result is very similar, but you add more boiler plate code to save realm into the store.

File 1

Realm.open({ schema: [Login] })
.then(realm => {
  this.saveRealm( realm )
});

Actions

saveRealm is an action:

export function saveRealm( realm ) {
  return {
    type: types.SAVE_REALM,
    realm
  }
}

Reducer

that will get handled in the reducer:

export default function reducer(state = initialState, action = {}) {

  switch (action.type) {
    case types.SAVE_REALM:
      return Object.assign({}, state, {
        realm: action.realm
      });

      //other actions
    default:
       return state;
  }

File 2

Finally in other file .js just use the saved realm instance, without having to open it again.

this.props.realm.write(() => {
    const isUser = this.props.realm.create('Login', { id: 1, token }, true);
   //rest of your code...
  });

You'll need to use mapStateToProps as usual:

function mapStateToProps(state) {
  return {
    realm: state.realm,

EDIT: Make the "Without Redux" the recommended option. Add more code example code to it.



回答2:

Sorry, I missed the Realm.open nuance in your question. I have been experimenting with the following and haven't run into any issues yet but I'm not sure it's the "right" way to do it.

import Realm from "realm";
import { fromPromise } from "rxjs/observable/fromPromise";
import { share, mergeMap } from "rxjs/operators";

export const realmUser$ = fromPromise(
  Realm.Sync.User.login(...)
).pipe(share())

export const realm$ = realmUser$.pipe(
  mergeMap(user =>
    Realm.open({...})
  ),
  share()
);

This module exports observables that represent the Realm user in addition to one or more opened realms. The exports of these modules can then easily be used elsewhere in your app.

import { realm$ } from "./sources/realm";
 
realm$.forEach(realm =>
  realm.write(() => {
    // TODO: Use the realm
  });
);

Hope this gives you some ideas. Also, in the Redux context, you don't need or want to store the realm itself in the store, but most likely a Realm.Result object. You can do that using redux-observable.

Original Answer

Does the example in the realm-js git repo not meet your needs?

Export a single realm:

import Realm from 'realm';

class Todo extends Realm.Object {}
Todo.schema = {
    name: 'Todo',
    properties: {
        done: {type: 'bool', default: false},
        text: 'string',
    },
};

class TodoList extends Realm.Object {}
TodoList.schema = {
    name: 'TodoList',
    properties: {
        name: 'string',
        creationDate: 'date',
        items: {type: 'list', objectType: 'Todo'},
    },
};

export default new Realm({schema: [Todo, TodoList]});

Import the realm in another file:

import realm from './realm';