Firestore错误-无法读取null的属性`firestore`

时间:2019-12-03 07:20:44

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

我尝试在身份验证后将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没有任何问题。

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

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

2 个答案:

答案 0 :(得分:2)

由于在文件中而不是在单个模块中进行多个Firebase导入/导出的问题,因此可能会发生错误。

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

因此,在firebase_utils中,您可以添加而不是:

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

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

您还可以从export default firebase;中删除firebase_utils,以防止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;

对于firebase的导入示例,您也可以参考this articlethis GitHub repo

答案 1 :(得分:1)

您必须使用已初始化的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();
....

美好的一天。