尝试使用 Realm 连接到 MongoDB

这是我第一次使用 Realm 和 MongoDB。 我以 good tutorial 为起点,创建了这个项目。

https://codesandbox.io/s/realm-forked-mrjex?file=/src/state/DbModel.ts

文件夹结构为:

src
|_ components
   |_ pages
      |_ Authentication.tsx
      |_ Home.tsx
      |_ Logout.tsx
   |_ App.tsx
   |_ Navigation.tsx
   |_ RestaurantCard.tsx
|_ lib
   |_ db-utils.ts
|_ state
   |_ index.ts
   |_ DbModel.ts

它们都是非常简单的组件,我在这里只发布其中的一部分。

App.tsx:

const serviceName = "mongodb-atlas";

export function App() {
  return (
    <Provider value={stateInstance}>
      <AppWithState />
    </Provider>
  );
}

function AppWithState() {
  const {
    db: { app,client,setClient,user,setUser }
  } = useMst();

  useEffect(() => {
    async function init() {
      if (!user) {
        const credentials = Realm.Credentials.anonymous();
        const newUser = app.currentUser
          ? app.currentUser
          : await app.logIn(credentials);
        setUser(newUser);
      }
      if (!client) {
        const newClient = app.currentUser.mongoClient(serviceName);
        setClient(newClient);
      }
    }
    init();
  },[app,user]);

  return (
    <Router>
      <Navigation />
      <Switch>
        <Route path="/" component={Home} />
        ...
      </Switch>
    </Router>
  );
}

状态/index.ts:

export const StateModel = t
  .model("StateModel",{
    db: t.optional(DbModel,{} as DbModelInstance)
  })
  .views((self) => ({}))
  .actions((self) => ({}));

export const stateInstance = StateModel.create();
export interface StateInstance extends Instance<typeof StateModel> {}

const RootStateContext = createContext<StateInstance | null>(null);
export const Provider = RootStateContext.Provider;

export function useMst() {
  const state = useContext(RootStateContext);
  if (state === null)
    throw new Error("State cannot be null,please add a context provider");
  return state;
}

状态/DbModel.ts:

const appId = process.env.REact_APP_REALM_APP_ID;
const appConfig: Realm.AppConfiguration = {
  id: appId
};
const app: Realm.App = new Realm.App(appConfig);

export const DbModel = t
  .model("DbModel",{
    app: t.optional(t.frozen<Realm.App>(),app),user: t.optional(t.frozen<Realm.User>(),null),client: t.optional(t.frozen<any>(),null)
  })
  .views((self) => ({
    get root() {
      return getRoot(self) as any;
    }
  }))
  .views((self) => ({}))
  .actions((self) => ({
    setapp(app: Realm.App) {
      self.app = app;
    },setUser(user: Realm.User) {
      self.user = user;
    },setClient(client: any) {
      self.client = client;
    }
  }))
  .actions((self) => ({}));

export interface DbModelInstance extends Instance<typeof DbModel> {}

Home.tsx:

export function Home() {
  const {
    db: { user,client }
  } = useMst();

  const [restaurants,setRestaurants] = useState([]);
  const isLoading = restaurants.length === 0;

  useEffect(() => {
    async function getData() {
      if (!client || !user) return;
      const rests = client.db("sample_restaurants").collection("restaurants");
      setRestaurants(await rests.find());
    }

    getData();
  },[isLoading,user]);

  if (isLoading) {
    return <div>HOME Loading...</div>;
  }

  return (
    <div>
      {restaurants.map((restaurant) => (
        <RestaurantCard key={restaurant._id} restaurant={restaurant} />
      ))}
    </div>
  );
}

Authentication.tsx:

const userSchema = yup.object().shape({
  email: yup.string().email().required(),password: yup.string().required().min(8)
});

export function Authentication({ type = "login" }) {
  const {
    db: { app,setUser,client }
  } = useMst();

  const [isLoading,setIsLoading] = useState(false);
  const history = useHistory();

  useEffect(() => {
    if (!isAnon(user)) {
      history.push("/");
    }
  },[history,user]);

  async function submitHandler(values: any) {
    setIsLoading(true);
    if (type === "create") {
      // @ts-ignore
      await app.emailPasswordauth.registerUser(values.email,values.password);
    }
    // login user and redirect to home
    const credentials = Realm.Credentials.emailPassword(
      values.email,values.password
    );
    // @ts-ignore
    setUser(await app.logIn(credentials));
    setIsLoading(false);
  }

  return (
    <Formik
      initialValues={{
        email: "",password: ""
      }}
      validationSchema={userSchema}
      onSubmit={submitHandler}
    >
      {({ errors,touched,handleSubmit,values,handleChange }) => (
        <Form noValidate onSubmit={handleSubmit}>
          {isLoading && <div classname="">AUTH Loading...</div>}

          <div>
            <h1>{type === "login" ? "Login" : "Sign Up"}</h1>
            <Form.Row>
              <Form.Label>Email</Form.Label>
              <Form.Control
                type="email"
                name="email"
                value={values.email}
                onChange={handleChange}
                isValid={touched.email && !errors.email}
              />
              <Form.Control.Feedback>{errors.email}</Form.Control.Feedback>
            </Form.Row>
            <Form.Row>
              <Form.Label>Password</Form.Label>
              <Form.Control
                type="password"
                name="password"
                value={values.password}
                onChange={handleChange}
                isValid={touched.password && !errors.password}
              />
              <Form.Control.Feedback>{errors.password}</Form.Control.Feedback>
            </Form.Row>

            <div classname="text-center mt-2">
              <Button variant="primary" type="submit">
                Submit
              </Button>
            </div>
          </div>
        </Form>
      )}
    </Formik>
  );
}

function isAnon(user: Realm.User) {
  return !user || user.identities[0].providerType === "anon-user";
}

基本上我使用了餐厅的示例数据库。 在教程中,作者使用 React 上下文来保存应用程序、用户和客户端等数据库信息,但我更喜欢设置 Mobx 状态树。我认为这是唯一的区别。 哦,我用的是 TypeScript(顺便说一句,client 的类型是什么?阅读指南我没看懂,好像是 MongoDB,但我需要从哪里导入它?)。

我的代码不起作用。 我什么也没得到,仍在加载:

尝试使用 Realm 连接到 MongoDB

我认为我的应用程序卡在 Home 组件中,在 getData() 函数中,因为 clientuser 都是 null,但在 {{1} }} 我创建了它们并保存在我的状态中,所以我不明白出了什么问题..

EDIT:有时,正如 Danila 所指出的,我也会收到此错误 App

我克隆了作者创建的 repo,它有效。我的代码有什么问题?我认为是 Promise 的问题,但我不确定,也不知道如何解决 :(

beijiao_1608 回答:尝试使用 Realm 连接到 MongoDB

您在 mobx-state-tree 中使用 DbModel.tstypes.frozen。 这与 Realm.App 混淆,因为内部 MongoDB Realm 代码正在尝试更改 Realm.App 实例,但由于您已冻结该实例,因此它将失败。

在您的应用代码中移动 Realm.App 创建应该可以解决问题。类似的东西:

function AppWithState() {
  const {
    db: {   client,setClient,user,setUser }
  } = useMst();
  const [app] = useState(new Realm.App(appConfig)) // <-- here is the fix,along with deleting the Realm.App instantiation code from DbModel.ts
 
  .... rest of your AppWithState code .....
}
本文链接:https://www.f2er.com/630.html

大家都在问