【问题标题】:Firestore Error - Cannot read property `firestore` of nullFirestore 错误 - 无法读取 null 的属性“firestore”
【发布时间】:2020-03-27 20:04:00
【问题描述】:

我正在尝试在身份验证后将 firestore 与我的 react 项目一起使用,以将一些数据写入 firebase。但是每当调用doc.set 时,我都会收到一条错误消息Cannot read property firestore of null

这是我的 firebase 配置文件。

import firebase from 'firebase/app';

const config = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
};

if (firebase.apps.length === 0) {
  console.log('Initializing firebase');
  firebase.initializeApp(config);
}

export default firebase;

这是我的 firebase utils 文件,我用它来访问 firebase 的常见要求。

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

import {FIREBASE_COLLECTIONS} from './constants';

export const getIdToken = async () => {
  try {
    const {currentUser} = firebase.auth();
    if (currentUser) {
      const idToken = await currentUser.getIdToken();
      return idToken;
    }
    return currentUser;
  } catch (error) {
    throw error || new Error('Error retrieving ID token');
  }
};

export const logout = async () => {
  try {
    await firebase.auth().signOut();
  } catch (error) {
    throw error || new Error('Error logging out');
  }
};

export const loginUser = async (email: string, password: string) => {
  try {
    const user = await firebase
      .auth()
      .signInWithEmailAndPassword(email, password);
    return user;
  } catch (error) {
    let message = '';
    switch (error.code) {
      case 'auth/invalid-email':
        message = 'Invalid Email Id';
        break;
      case 'auth/user-disabled':
        message = 'User is temporarily disabled';
        break;
      case 'auth/user-not-found':
        message = 'User not found. Please register';
        break;
      case 'auth/wrong-password':
        message = 'Incorrect password';
        break;
      default:
        message = 'Error logging in';
        break;
    }
    throw new Error(message);
  }
};

export const registerUser = async (email: string, password: string) => {
  try {
    const user = await firebase
      .auth()
      .createUserWithEmailAndPassword(email, password);
    return user;
  } catch (error) {
    const errorCode = error.code;
    let message = '';
    switch (errorCode) {
      case 'auth/email-already-in-use':
        message = 'Email already in use';
        break;
      case 'auth/invalid-email':
        message = 'Invalid email ID';
        break;
      case 'auth/weak-password':
        message = 'Weak password';
        break;
      default:
        message = 'Error registering user';
        break;
    }
    throw new Error(message);
  }
};

export const signInWithGoogle = async () => {
  const provider = new firebase.auth.GoogleAuthProvider();
  provider.setCustomParameters({prompt: 'select_account'});
  const scopes = ['profile', 'email'];
  scopes.forEach(scope => provider.addScope(scope));
  try {
    return await firebase.auth().signInWithPopup(provider);
  } catch (error) {
    let message = '';
    switch (error.code) {
      case 'auth/account-exists-with-different-credential':
        message = 'Account exists with another sign in type';
        break;
      case 'auth/popup-closed-by-user':
        message = 'Login popup closed';
        break;
      default:
        message = 'Error signing in';
        break;
    }
    throw new Error(message);
  }
};

export const isLoggedIn = (): boolean => {
  const {currentUser} = firebase.auth();
  return currentUser !== null;
};

export const getUserDoc = (
  id: string
): firebase.firestore.DocumentReference => {
  return firebase
    .firestore()
    .collection(FIREBASE_COLLECTIONS.USERS)
    .doc(id);
};

export default firebase;

我正在从 firebase utils 调用 getUserDoc 函数并使用它向用户写入数据。

function* registerWithPassword(user: UserInput) {
  try {
    const userData: firebase.auth.UserCredential = yield call(
      registerUser,
      user.email,
      user.password
    );
    if (userData === null || userData.user === null) {
      yield put(
        authFailureAction.failure({
          register: 'Unable to register user',
        })
      );
    } else {
      const userDoc = getUserDoc(userData.user.uid);   
      yield call(
        userDoc.set,
        {labels: [], pinnedNotes: [], name: user.name},
        {merge: true}
      );
    }
  } catch (e) {
    console.log({e});
    yield put(
      authFailureAction.failure({
        register: e.message || 'Unable to register user',
      })
    );
  }
}

当调用userDoc.set 时,会发生错误。 从一些调试来看,firebase 似乎为空。这就是firebase.firestore() 抛出错误的原因。 但如果 firebase 为 null,auth 也不应该工作,但我对 firebase auth 没有任何问题。

还要注意我在我的index.js 文件中导入firebaseConfig.js,所以我确定firebase 已经初始化。这也是因为用户正在注册,但由于某种原因,当我从firebase.firestore() 访问firestore 时,firebase 为空。

您可以访问项目here。尝试注册一个用户,你会看到错误。由于它依赖于 Firebase,因此您必须添加相关的 .env 文件。

【问题讨论】:

  • 我对这个导入语法有一些疑问:import firebase from 'firebase/app'; import 'firebase/auth'; 目前还无法重现,但您是否可能只正确导入了 auth 模块?
  • 没有人。我正在导入firebase/firestore。当身份验证有效时,当我尝试使用 firestore 时,firebase 不应为空。

标签: firebase google-cloud-platform google-cloud-firestore


【解决方案1】:

该错误可能是由于文件中完成的多个 Firebase 导入/导出问题而不是单个模块作为源的问题。

firebase 模块只能在firebase_config 文件中导出,然后从那里导入到其他文件中。

所以在firebase_utils,你可以添加:

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

import firebase from './firebase-config.js';

您还可以从firebase_utils 中删除export default firebase;,以防止firebase 命名空间被覆盖。

所以最终的firebase_config.js 文件可能如下所示:

// Firebase App (the core Firebase SDK)
var firebase = require("firebase/app");

// Add the Firebase products that you want to use
require("firebase/auth");
require("firebase/firestore");

// Your app's Firebase project configuration
var firebaseConfig = {
  // ...
};

// Initialize Firebase
firebase.initializeApp(firebaseConfig);

// Single source for all imports of the firebase module
export default firebase;

您也可以参考this articlethis GitHub repofirebase 导入示例。

【讨论】:

  • 试过了,伙计。它不起作用。仍然出现同样的错误。
  • 从上面提到的细节中评论可能发生的事情有点困难。你可以发一个minimum reproducible example 吗?
  • 在问题中添加了项目链接。我希望这会有所帮助。
【解决方案2】:

你必须使用已经初始化的firebase。

import firebase from 'firebase/app'; <-- This one hasn't been initialized.
...
firebase.initializeApp(firebaseConfig);
export default firebase; <-- This one is initialized.

在您的 firebase_config 中,添加 firestore 和身份验证

import firebase from 'firebase/app';
import 'firebase/auth';      <----- add this here.
import 'firebase/firestore'; <----- add this here.

const config = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
};

if (firebase.apps.length === 0) {
  console.log('Initializing firebase');
  firebase.initializeApp(config);
}

export default firebase;

更改前 3 行。

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

import {FIREBASE_COLLECTIONS} from './constants';

export const getIdToken = async () => {
  try {
    const {currentUser} = firebase.auth();
    if (currentUser) {
      const idToken = await currentUser.getIdToken();
....

import firebase from './firebase_config.js'; // or wherever your firebase.initializeApp(...) live.

import {FIREBASE_COLLECTIONS} from './constants';

export const getIdToken = async () => {
  try {
    const {currentUser} = firebase.auth();
    if (currentUser) {
      const idToken = await currentUser.getIdToken();
....

美好的一天。

【讨论】:

  • 不工作的人。这个也试过了。我从 firebase_config 方法继续前进,因为它不起作用。所以我认为单独的导入会起作用。
  • @Doppio 被意外否决了。我认为这是问题的原因。每个 firebase 子模块都必须在初始化之前导入一次。请进行编辑以取消投票。
  • @ChristosLytras 收回反对票是什么意思?那是一回事吗? O.O
  • @Doppio 当然,您可以在编辑后收回否决票和赞成票,如果您考虑一下,这是非常合乎逻辑的,因为在编辑后错误的答案可能是正确的答案。只需在代码中稍作修改即可。
  • 你得到了 +1。我本可以自己编辑,但我不喜欢那样做。检查这个关于它的元帖子:meta.stackoverflow.com/questions/260017/…
猜你喜欢
  • 2019-10-19
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 2017-06-07
  • 2021-08-29
  • 1970-01-01
相关资源
最近更新 更多