The NextJS app was working fine a few days ago and now giving the following error. Nothing has changed in backend and table still exists.
Unhandled Runtime Error
FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
My firebase config file
import { initializeApp, getApp, getApps } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
import { getStorage } from 'firebase/storage';
const firebaseConfig = {
apiKey: XXX,
authDomain: XXX,
projectId: XXX,
storageBucket: XXX,
messagingSenderId: XXX,
appId: XXX,
measurementId: XXX,
};
const app = !getApps().length ? initializeApp(firebaseConfig) : getApp();
const auth = getAuth(app);
const db = getFirestore(app);
const storage = getStorage(app);
export { app, auth, db, storage };
And the useEffect inside the function component
import React, { useEffect, useState } from "react";
import {
onSnapshot,
collection,
addDoc,
getDocs,
orderBy,
query,
where,
limit,
QuerySnapshot,
} from "firebase/firestore";
import { db } from "../../config/firebase";
const [users, setUsers] = useState([]);
useEffect(() => {
const q = query(
collection(db, "user_info"),
orderBy("name", "asc")
);
getDocs(q).then((querySnapshot) => {
const docs = [];
querySnapshot.forEach((doc) => {
docs.push(doc.data());
});
setUsers(docs);
});
}, []);
Also, tried using #useCollectionData from 'react-firebase-hooks', however, the same error happens.
#This works
console.log(db)
const myCollectionRef = collection(db, 'users');
const myCollectionQuery = query(myCollectionRef);
const [users, reactloading, reacterror] = useCollectionData(myCollectionQuery);
#This does not
console.log('users',users)
Seems like the app works fine as in getting data in the pages at root level, however, the firestore collection and query function breaks if used in the nested route.
Related
I am using NextJS and Firebase fairly new to both. My app is trying to collect data from firestore database on some occasions it works fine and sometimes it returns "n is undefined" refering to the firestore object "db". This happens when i call the "collection(db, "users", uid, "posts")" function in the [posts].js file. What is causing this?
Firebase.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import {getStorage} from "firebase/storage"
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxx",
projectId: "xxxxxxxxxxxxxxxxxxxx",
storageBucket: "xxxxxxxxxxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const storage = getStorage(app);
export const db = getFirestore(app);
[posts].js
import { useRouter } from 'next/router'
import { useState, useEffect } from 'react';
import Link from 'next/link';
import { useAuth } from '../context/AuthContext'
import styles from '../styles/dashboard.module.css';
import Image from 'next/image';
import { collection, getDocs } from "firebase/firestore";
import { db } from '../lib/firebase';
export default function Posts(){
const [queriedData, setQueriedData] = useState([]);
const router = useRouter()
const { uid } = router.query
useEffect(() => {
async function fetchData() {
const postsRef = collection(db, "users", uid, "posts");
const snapshot = await getDocs(postsRef);
const postData = snapshot.docs.map((doc) => {
const data = doc.data();
data.id = doc.id;
return data;
});
setQueriedData(postData);
}
fetchData();
}, []);
return(
{queriedData.map((post) =>(<div>post.title</div>)
)}
}
Added await to the collection function and I also thought it was internet issues hence i setup a firebase emulator still got the same behavior.
I tried console logging "db" right after the line "export const db = getFirestore(app);". I got out "[Object Object]"
I’m building a financial dashboard with React that is tested with React-testing-library / Jest, and connected to Firebase for authentication and its Realtime Database.
My issue I’m having is during testing:
In my Transactions file, I have a useEffect that updates an allTransactions State with the transactions in that users database, the users id/auth is being tracked by useAuthState (stored in the var user.uid, users must login before using the dashboard).
My tests fail because there is no user specified (an empty user.uid) to get the transactions from to eventually display them.
How do I go about having a user.uid available for when my tests run?
Transactions.js
import React, { useEffect, useState } from 'react';
import { getDatabase, ref, onValue, remove } from "firebase/database";
import { useAuthState } from 'react-firebase-hooks/auth';
import { auth } from '../../config/Firebase';
const [ allTransactions, setAllTransactions ] = useState([]);
const [ user ] = useAuthState(auth);
useEffect(()=> {
const db = getDatabase();
const dbRef = ref(db,'transactions/' + user.uid);
onValue(dbRef, (snapshot) => {
snapshot.forEach((childSnapshot) => {
const childData = childSnapshot.val();
// if snapshot id is found in the alltransactions array dont add it
let check = allTransactions.some(item => item.id === childData.id);
if(!check){
let oldTransactions = allTransactions;
oldTransactions.push(childData);
setAllTransactions(oldTransactions);
}
})});
}, []);
Transactions.test.js
import { render, screen, cleanup } from '#testing-library/react';
import Transactions from './Transactions';
afterEach(cleanup);
test('Transactions component renders', () => {
render(<Transactions />);
expect(screen.getByText('Transactions')).toBeInTheDocument();
});
Firebase.js Config
import { initializeApp } from "firebase/app";
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: process.env.REACT_APP_API_KEY,
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
projectId: process.env.REACT_APP_PROJECT_ID,
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID
};
// Initialize Firebase
initializeApp(firebaseConfig);
export const auth = getAuth();
Failing test error
I'm expecting to be able to test my code, even if that means I need to mock data or run it with an emulator. I eventually want to be able to test writing to, deleting from the database, and displaying the info in the database.
It may be a fundamental concept but I can't find anything to my issue.
const userDoc = getUserWithUID(auth.currentUser.uid);
Cannot read property 'uid' of null
import ImageUploader from "../components/ImageUploader";
import {auth, getUserWithUID, postToJSON} from "../lib/firebase";
import {useContext} from "react";
import {UserContext} from "../lib/context";
export async function getServerSideProps(context) {
const userDoc = getUserWithUID(auth.currentUser.uid);
return {props: {userDoc}} ;
}
export default function SettingsPage() {
return (
<main>
<ImageUploader></ImageUploader>
</main>
)
/ Firebase lib file
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import 'firebase/storage';
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_API_KEY,
authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_APP_ID,
measurementId: process.env.NEXT_PUBLIC_MEASUREMENT_ID
};
if(!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
export const auth = firebase.auth();
export const googleAuthProvider = new firebase.auth.GoogleAuthProvider();
export const firestore = firebase.firestore();
// Storage exports
export const storage = firebase.storage();
export const STATE_CHANGED = firebase.storage.TaskEvent.STATE_CHANGED;
export const fromMillis = firebase.firestore.Timestamp.fromMillis;
export const serverTimestamp = firebase.firestore.FieldValue.serverTimestamp;
/**`
* Gets a users/{uid} document with company
* #param {string} company
*/
export async function getUserWithCompany(company) {
const usersRef = firestore.collection('users');
const query = usersRef.where('company', '==', company).limit(1);
const userDoc = (await query.get()).docs[0];
return userDoc;
}
export async function getUserWithUID(uid) {
const userDoc = await firestore.collection('users').doc(uid).get();
return userDoc;
}
As far as my understanding goes, getServerSideProps() is only executed on the server and therefore has no access to frontEnd Data such as the Google authentication token and the corresponding userID. Hope this helps, even though you asked one month ago. :)
I'm pretty new to react and firebase. I implemented a login/auth system with firebase, and I was trying to take this to the next level: implement a profile page with profile picture. I followed a youtube tutorial and it seemed pretty easy,but somehow I'm getting a firebase error, and I assume something changed since the release of that tutorial! I don't really know what is going on, please help me fix this and explain me like I'm 5!
(update profile picture file)
ProfilePicture.js:
import React, {useEffect, useState} from 'react'
import {useAuth} from '../authentication/AuthContext'
import upload from '../../config/firebase'
export default function ProfilePicture() {
const currentUser = useAuth()
const [photo, setPhoto] = useState(null)
const [loading, setLoading] = useState(false)
const [photoURL, setPhotoURL] = useState("https://upload.wikimedia.org/wikipedia/commons/7/7c/Profile_avatar_placeholder_large.png")
function handleChange(e){
if (e.target.files[0]){
setPhoto(e.target.files[0])
}
}
function handleClick(){
upload(photo, currentUser, setLoading)
}
useEffect(()=>{
if (currentUser && currentUser.photoURL){
setPhotoURL(currentUser.photoURL)
}
}, [currentUser])
return (
<>
<input type="file" onChange={handleChange} />
<button disabled={loading || !photo} onClick={handleClick}>Upload</button>
<img src={photoURL} alt="Avatar" className='avatar'/>
</>
)
}
firebase.js
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import 'firebase/firestore'
import { getStorage, ref, uploadBytes } from 'firebase/storage';
const app = firebase.initializeApp({
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,
appId: process.env.REACT_APP_FIREBASE_APP_ID
})
export const auth = firebase.auth();
export const firestore = firebase.firestore();
export const storage = getStorage();
//storage
export async function upload(file, currentUser, setLoading){
const fileRef = ref(storage, currentUser.uid + '.png')
setLoading(true)
const snapshot = await uploadBytes(fileRef, file)
setLoading(false)
alert("Uploaded File!")
}
export const createUserDocument = async (user, additionalData) => {
if (!user) return;
const userRef = firestore.doc(`users/${user.uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { email } = user;
const { displayName } = additionalData;
try {
await userRef.set({
displayName,
email,
createdAt: new Date(),
});
} catch (error) {
console.log('Error creating user', error);
}
}
};
export default app
the error:
You are mixing up firebase compat version with the latest firebase modular version
The following lines are not needed.
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import 'firebase/firestore'
https://firebase.google.com/docs/web/modular-upgrade
You may want to revisit the documentation, and only follow the codes under version 9 modular.
For example, to initialize the app, the correct codes for version 9 modular will be something like this.
import { initializeApp, getApps } from "firebase/app"
var firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECTID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGEBUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID
};
For authentication you need to use getAuth
For example
import firebase from 'src/firebase/firebase'
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
const auth = getAuth(firebase);
export async function loginPassword(email, password) {
return await signInWithEmailAndPassword(auth, email,password)
}
Reference: https://firebase.google.com/docs/auth/web/password-auth
Please follow the codes from v9 modular
Installed firebase via command npm i firebase. Also tried npm i firebase#8.1.1 (Nov2020 version in which the tutorial has used firebase) and npm i firebase --save to no avail.
Here is my Stackblitz project link for your reference.
S.O.S.
Please have a look at the documentation: https://firebase.google.com/docs/web/setup
Your firebase.js should look like this
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore/lite';
const firebaseConfig = {
apiKey: 'AIzaSyCUCwjxhnH-D99j1dKmI-tyL3Q057FI1WA',
authDomain: 'cp-react-robinhood.firebaseapp.com',
projectId: 'cp-react-robinhood',
storageBucket: 'cp-react-robinhood.appspot.com',
messagingSenderId: '112144437320',
appId: '1:112144437320:web:bf5dd8d3a3f0d83bc6c87d',
measurementId: 'G-NLE375QG7B',
};
const firebaseApp = initializeApp(firebaseConfig);
const db = getFirestore(firebaseApp);
export { db };
Your Stats.js should start like this:
import React, { useState, useEffect } from 'react';
import './Stats.css';
import axios from 'axios';
import StatsRow from './StatsRow';
import { db } from './firebase';
import { collection, getDocs } from 'firebase/firestore/lite';
// f u
function Stats() {
const TOKEN = 'bvkgi0v48v6vtohioj2g';
const BASE_URL = 'https://finnhub.io/api/v1/quote';
const [stockData, setstockData] = useState([]);
const [myStocks, setmyStocks] = useState([]);
const getMyStocks = () => {
const myStocksCollection = collection(db, 'cities');
getDocs(myStocksCollection).then((snapshot) => {
let promises = [];
let tempData = [];
snapshot.docs.map((doc) => {
console.log(snapshot.docs);
promises.push(
getStocksData(doc.data().ticker).then((res) => {
tempData.push({ id: doc.id, data: doc.data(), info: res.data });
})
);
});
});
};
You just imported firebase the wrong way. You have to import each module which you will need for you purpose.