NextJs getServerSideProps cannot fetch data from Cloud Firestore Web version 9 - javascript

I am using NextJs version 12.0.10 and firebase version 9.6.6 which use a modular system to import it.
When I run the function from my service to fetch data from firebase/firestore, it returns an error saying Cannot access 'getStories' before initialization. I'm confident all the logic & syntax are correct, as it works perfectly when I fetch it from inside the page render function.
Here is my getServerSideProps function:
pages/index.js
import '#uiw/react-markdown-preview/markdown.css';
import { useContext } from 'react';
import { getStories } from '../lib/services/StoryService';
import { truncate } from 'lodash';
import { convertSecondsToHumanReadableDiff } from '../lib/utils/common';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { AuthContext } from '../pages/_app';
import Navigation from '../components/Navigation';
export async function getServerSideProps() {
const fetchedStories = await getStories();
const stories = fetchedStories.docs.map((story) => {
return {
...story.data(),
id: story.id,
content: truncate(story.data().content, { length: 150, separator: '...' }),
};
});
return { props: { stories } };
}
const Blog = ({ stories }) => {
const router = useRouter();
const { user } = useContext(AuthContext);
return (
<div>
...
</div>
);
};
export default Blog;
lib/firebase/firebase.js
import { initializeApp } from 'firebase/app';
import { getAnalytics } from 'firebase/analytics';
import { getFirestore } from 'firebase/firestore';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: 'XXX',
authDomain: 'XXX',
projectId: 'XXX',
storageBucket: 'X',
messagingSenderId: 'XXX',
appId: 'XXX',
measurementId: 'XXX',
};
const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
export const database = getFirestore(app);
export const auth = getAuth(app);
lib/services/storyService.js
import {
collection,
query,
getDocs,
getDoc,
setDoc,
doc,
serverTimestamp,
orderBy,
} from 'firebase/firestore';
import { database } from '../firebase/firebase';
import slugify from 'slugify';
import { random } from 'lodash';
const storiesRef = collection(database, 'stories');
export const createStory = async (payload) => {
const slugTitle = slugify(payload.title);
const slug = slugTitle + '-' + random(0, 100000);
const updatedPayload = {
...payload,
slug,
type: 'published',
createdAt: serverTimestamp(),
};
return setDoc(doc(storiesRef, slug), updatedPayload);
};
export const getStories = async () => {
const q = query(storiesRef, orderBy('createdAt', 'desc'));
return getDocs(q);
};
export const getStoryBySlug = async (slug) => {
const docRef = doc(database, 'stories', slug);
return getDoc(docRef);
};

You are using getDocs, a client-side function of firebase, inside your getStories function, which is invoked in getServerSideProps, a node.js environment.
Instead you need to use the admin SDK for functions invoked in node.js environment (like getServerSideProps), e.g. like so:
import * as admin from "firebase-admin/firestore";
export const getStories = async () => {
return await admin
.getFirestore()
.collection(database, 'stories')
.orderBy('createdAt', 'desc')
.get()
};
export const getStoryBySlug = async (slug) => {
return await admin
.getFirestore()
.doc(database, 'stories', slug)
.get()
};
(sorry for the late answer, I still hope it helps OP or anyone else)

Related

Firestore get count for a collection not working

I have this code:
import { getCountFromServer } from 'firebase/firestore'
useEffect(()=> {
const getCount = async () => {
const collection = userDB().collection('invoices')
const query = collection.where('status', '==', 'paid')
const snapshot = await getCountFromServer(query)
setCount(snapshot.data().count)
}
getCount().catch(err=> console.log(err))
}, [user, collectionRef, filterKey, filterValue])
Where userDB() is the same as db.collection('users').doc(userid')
Yet this throughs an error:
TypeError: Cannot read properties of undefined (reading '_t')
at gn (index.esm2017.js:4251:1)
at bu (index.esm2017.js:13685:1)
at Ca.run (index.esm2017.js:16797:1)
at index.esm2017.js:20050:1
I have followed the docs: https://firebase.google.com/docs/firestore/query-data/aggregation-queries#web-version-9_1
Currently using:
"firebase": "^9.15.0",
userDB is defined in a ts file like so:
export const userDB = () => {
let user = auth.currentUser
return db.collection('users').doc(user?.uid)
}
Here is the initlizer file:
import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import 'firebase/compat/auth';
const firebaseApp = firebase.initializeApp ({
...keys
});
export const Providers = {
google: new firebase.auth.GoogleAuthProvider(),
};
const db = firebaseApp.firestore()
const auth = firebase.auth();
const Fire = firebaseApp
export {db, Fire, auth}
You should not uses both compat and modular SDKs together. The compat version does not support count queries. I would recommend updating your code to use the new syntax:
import { initializeApp } from 'firebase/app';
import { getFirestore } 'firebase/firestore';
import { getAuth, GoogleAuthProvider } 'firebase/auth';
const firebaseApp = initializeApp({
...keys
});
export const Providers = {
google: new GoogleAuthProvider(),
};
const db = getFirestore()
const auth = getAuth();
export { db, auth }
import { db } from '...'
import { collection, query, where, getCountFromServer } from 'firebase/firestore'
useEffect(()=> {
const getCount = async () => {
const q = query(collection(db, 'invoices'), where('status', '==', 'paid'))
const snapshot = await getCountFromServer(q)
setCount(snapshot.data().count)
}
getCount().catch(err=> console.log(err))
}, [user, collectionRef, filterKey, filterValue])

Why firebase give this error when I use onSnapshot?

Error itself : Uncaught FirebaseError: Expected type 'pa', but it was: a custom $n object
firebase file :
import { initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'
import { getFirestore } from 'firebase/firestore/lite'
const firebaseConfig = {
apiKey: 'API_KEY',
authDomain: 'AUTH_DOMAIN',
projectId: 'PROJECT_ID',
storageBucket: 'STORAGE_BUCKET',
messagingSenderId: 'MESSAGING_SENDER_ID',
appId: 'APP_ID',
}
const firebaseApp = initializeApp(firebaseConfig)
const db = getFirestore(firebaseApp)
const auth = getAuth(firebaseApp)
export { db, auth }
Request itself :
useEffect(() => {
//getPosts()
const unsubscribe = onSnapshot(collection(db, 'cities'), (snapshot) => {
const postsList = snapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
setPosts(postsList)
})
return () => {
unsubscribe()
}
}, [])
I tried to change some imports like other recommend but just got another error
Firestore Lite SDK does not support listeners. Try importing getFirestore() from the standard SDK.
import { initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'
import { getFirestore } from 'firebase/firestore' // <-- remove /lite
const firebaseConfig = {...}
const firebaseApp = initializeApp(firebaseConfig)
const db = getFirestore(firebaseApp)
const auth = getAuth(firebaseApp)
export { db, auth }
import { db } from './path/to/firebase';
import { collection, onSnapshot } from 'firebase/firestore';
useEffect(() => {
const unsubscribe = onSnapshot(collection(db, 'cities'), (snapshot) => {
const postsList = snapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
setPosts(postsList)
})
}, [])

How to listAll items inside firebase folder react?

I have a folder in Firebase storage called "dataset" where I have some PDF documents which I'm trying to display them here but it's not working please help me figure out the issue?
In below code I have write the code to get the available documents from "datase/" folder.
import React, {useState, useEffect} from 'react';
import { storage } from "../config/firebase";
import { ref, listAll, getDownloadURL } from "firebase/storage"
function ForwardPE() {
const fetchImages = async () => {
const storageRef = await ref(storage, "dataset");
const result = await listAll(listRef);
const urlPromises = result.items.map((imageRef) => getDownloadURL(imageRef));
return Promise.all(urlPromises);
};
const loadImages = async () => {
const urls = await fetchImages();
console.log(urls)
setFiles(urls);
};
loadImages()
return (
<>
</>
);
};
export default ForwardPE;
Firebase.js Code
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getAnalytics } from "firebase/analytics";
import { getStorage } from "firebase/storage";
const firebaseConfig = {
apiKey: "AIzaSyAqW6kUwy4VGS8iBb72lXqK0v3ZnxR_Ohk",
authDomain: "ai-web-app-1eba6.firebaseapp.com",
projectId: "ai-web-app-1eba6",
storageBucket: "ai-web-app-1eba6.appspot.com",
messagingSenderId: "488293461041",
appId: "1:488293461041:web:62aec35f6d5e09a0e63910"
};
const firebaseApp = initializeApp(firebaseConfig);
export const storage = getStorage();
export const firebaseAuth = getAuth(firebaseApp);
export const firebaseAnalytics = getAnalytics(firebaseApp);
Console Error:
You are using the new Firebase Modular SDK (v9.0.0) that has a functional syntax and unlike the older name-spaced one. Try refactoring the code as shown below:
// firebase.js
import { getStorage } from "firebase/storage";
// ... initialise other services
export const storage = getStorage();
import { storage } from "../path/to/firebase.js"
import { ref, listAll, getDownloadURL } from "firebase/storage"
const fetchImages = async () => {
const storageRef = await ref(storage, "dataset");
const result = await listAll(listRef);
const urlPromises = result.items.map((imageRef) => getDownloadURL(imageRef));
return Promise.all(urlPromises);
};
const loadImages = async () => {
const urls = await fetchImages();
console.log(urls)
setFiles(urls);
};
loadImages()
Checkout the documentation for more information and refer to namespace tab.

Can't use firebase in React component, because it's not initialized [duplicate]

I am making a food delivery app using react-native and redux. I want to fetch the data from the firebase store and for that, I have written a function in the actions.js, but whenever I run the app it shows the Error
Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
Here is the function which I am using to fetch the data
action.js
import firebase from "firebase"
export const ProductDetails = (data) => {
return {
type: "PRODUCT_ITEMS",
payload: {
data,
},
};
};
var db = firebase.firestore();
var docRef = db.collection("Products").doc("Items");
export const FetchItems = () => {
return async function (dispatch) {
return await docRef
.get()
.then((doc) => {
if (doc.exists) {
console.log("Document Data", doc.data());
dispatch(ProductDetails(doc.data));
} else {
console.log("NO such document");
}
})
.catch((error) => {
console.log(error);
});
};
};
Here is my App.js file
import React, { useState } from "react";
import { StyleSheet, Text, View, Dimensions } from "react-native";
import { NavigationContainer } from "#react-navigation/native";
import AppStack from "./components/navigation/AppStack";
import firebase from "firebase";
import {Provider} from "redux"
import store from "./store"
import { useDispatch, useSelector, Provider } from "react-redux";
import store from "./redux/store";
import AppWrapper from "./AppWrapper";
export default function App() {
const firebaseConfig = {
};
if (firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
return (
<Provider store={store}>
<NavigationContainer>
<AppStack />
</NavigationContainer>
</Provider>
);;
}
I would recommend creating a separate file firebase.js and export Firebase services from there after initialization.
firebase.js
import firebase from 'firebase/app';
import 'firebase/firestore'
const firebaseConfig = {...};
if (!firebase.apps.length) {
firebase.initializeApp(config);
}
export const auth = firebase.auth();
export const firestore = firebase.firestore()
Then import these wherever you need them:
// App.js for example
import {firestore, auth} from './firebase.js'
//var docRef = firestore.collection("Products").doc("Items");
for users with expo(v44) and firebase(v9)
firebaseUtil.js
import { initializeApp, getApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";
// Initialize Firebase
const firebaseConfig = {
...
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const auth = getAuth(app);
export { db, auth };
Login.js
import { auth } from "../../util/firebaseUtil";
export default function Login() {
const onSignUp = () => {
signInWithEmailAndPassword(auth, email, password);
};
return (
...
)
}
I think my error is caused by Webpack chunking(bootstrap). I did import the file with initializeApp(). My work around for who has the same problem.
Modularize the initializeApp in one file(initFire for me) and export anything(doesn't have to be app)
Import & Export before first usage of getApp()(methods like getAuth() will call it),
In this way, after Webpack it will still run first. (ES6 export {app} from "./initFire")
(This answer is grepped from my own GitHub Wiki, not plagiarizing)

NextJS Firebase Auth undefined GoogleAuthProvider

I am having issues implementing firebase authentication with Google Provider in NextJS. I set up the environment variables and am successfully connecting to firebase. I am receiving the following error and cant seem to figure out a solution, TypeError: Cannot read properties of undefined (reading 'GoogleAuthProvider'). Below is my code.
//firebaseApp.js
import { initializeApp, getApps } from "firebase/app"
import { getFirestore } from "firebase/firestore"
import { getAuth } from "firebase/auth"
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
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,
};
if (getApps().length === 0) {
console.log('Error Connecting to Firebase')
}
const app = initializeApp(firebaseConfig)
const db = getFirestore(app)
const auth = getAuth(app)
export { db, auth }
//firebaseAuthUI.config.js
export const uiConfig = (firebase) => {
return {
signInFlow: "popup",
signInSuccessUrl: "/",
signInOptions: [firebase.auth.GoogleAuthProvider.PROVIDER_ID],
};
};
//login.js
import Head from 'next/head';
import { useRouter } from 'next/router';
import { useAuthState } from 'react-firebase-hooks/auth';
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
import { auth, firebase } from '../app/firebaseApp';
import { uiConfig } from '../config/firebaseAuthUI.config';
export default function Login() {
const [user, loading, error] = useAuthState(auth);
const router = useRouter();
if (loading) return 'loading'
else if (error) return error
else if (user) {
router.push('/');
}
const authConfig = uiConfig(auth);
return (
<>
<Head>
<title>Login</title>
</Head>
<StyledFirebaseAuth uiConfig={authConfig} firebaseAuth={auth} />
</>
)
}
I think the example code you copy from uses module 8
try to import GoogleAuthProvider like this, check firebase ref
import { GoogleAuthProvider} from "firebase/auth"
...
...
export const uiConfig = (firebase) => {
return {
signInFlow: "popup",
signInSuccessUrl: "/",
signInOptions: [GoogleAuthProvider.PROVIDER_ID],
};
};

Categories