Why firebase onAuthStateChanged always return a null value? - javascript

import firebase from "firebase/app";
import "firebase/auth";
import firebaseConfig from '../../FirebaseConfig';
import { useEffect, useState } from 'react';
if(!firebase.apps.length){
firebase.initializeApp(firebaseConfig);
}
const AuthChange = () => {
const [UserInfo, setUserInfo] = useState();
useEffect(() => {
firebase.auth().onAuthStateChanged(function(user) {
console.log('AuthChanged', user)
if (user) {
const information = {name: user.displayName}
setUserInfo(information);
} else {
setUserInfo(null);
}
});
}, [])
return UserInfo;
}
export default AuthChange;
The output is
Authentication.js:14 AuthChanged null
.
The output is always null, whether the user is signed in or not. How can I solve It?

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])

Unable to process request due to missing initial state( Firebase)

A user of my website encountered an error message while attempting to sign up using GitHub on my React site from his chrome browser(mobile). I have integrated Firebase GitHub sign-in with the popup method.
Unable to process request due to missing initial state. This may happen if browser sessionStorage is inaccessible or accidentally cleared.
Code for signup:
import { useEffect, useState } from "react"
import { GithubAuthProvider, signInWithPopup } from "firebase/auth"
import { auth } from "../firebase/config"
import { createUserProfileDocument } from "../firebase/createUserProfileDocument"
import { useAuthContext } from "./useAuthContext"
export const useSignup = () => {
const [error, setError] = useState(false)
const [isPending, setIsPending] = useState(false)
const [isCancelled, setIsCancelled] = useState(false)
const provider = new GithubAuthProvider()
const { dispatch } = useAuthContext()
const signup = async () => {
setError(null)
setIsPending(true)
try {
const res = await signInWithPopup(auth, provider)
if (!res) {
throw new Error("Could not complete signup")
}
const user = res.user
await createUserProfileDocument(user)
dispatch({ type: "LOGIN", payload: user })
if (!isCancelled) {
setIsPending(false)
setError(null)
}
} catch (error) {
if (!isCancelled) {
setError(error.message)
setIsPending(false)
}
}
}
useEffect(() => {
return () => setIsCancelled(true)
}, [])
return { signup, error, isPending }
}
useAuthContext code:
import { useContext } from "react"
import { AuthContext } from "../context/AuthContext"
export const useAuthContext = () => {
const context = useContext(AuthContext)
if (!context) {
throw Error("useAuthContext must be used inside an AuthContextProvider")
}
return context
}
AuthContext code
import { createContext, useEffect, useReducer } from "react"
import { onAuthStateChanged } from "firebase/auth"
import { auth } from "../firebase/config"
import { authReducer } from "../reducers/authReducer"
export const AuthContext = createContext()
export const AuthContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(authReducer, {
user: null,
authIsReady: false,
})
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
dispatch({ type: "AUTH_IS_READY", payload: user })
})
return unsubscribe
}, [])
return (
<AuthContext.Provider value={{ ...state, dispatch }}>{children}</AuthContext.Provider>
)
}
firebaseConfig object:
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,
}
initializeApp(firebaseConfig)
const db = getFirestore()
const auth = getAuth()
export { auth, db, logEvent }

NextJs getServerSideProps cannot fetch data from Cloud Firestore Web version 9

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)

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)

I am trying to history.push but its always undefined on react

I am trying to history.push but its always undefined.
import React, { useEffect, useState } from "react";
import * as Firebase from "firebase/app";
import "firebase/auth";
import DBAPI from "./database/database-api"
import DBName from "./database/database-name"
import { useHistory } from "react-router-dom";
export const UserContext = React.createContext();
export const UserProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const [isAdmin, setIsAdmin] = useState(null);
const [isVendor, setIsVendor] = useState(null);
const [pending, setPending] = useState(true);
let history = useHistory();
useEffect(() => {
Firebase.auth().onAuthStateChanged(async (user) => {
if (user != null) {
setCurrentUser(user)
let response = await Promise.all([
DBAPI.checkUserExist(DBName.admin, user.uid),
DBAPI.checkUserExist(DBName.vendor, user.uid)
]);
console.log(response[0].data)
console.log(response[1].data)
if (response[0].data) setIsAdmin(true) // admin
if (response[1].data) setIsVendor(true) // vendor
history.push(`${process.env.PUBLIC_URL}/products`)
} else {
setIsVendor(false)
setIsAdmin(false)
}
setPending(false)
});
}, []);
if(pending){
return <>Loading...</>
}
return (
<UserContext.Provider
value={{
currentUser,
isAdmin,
isVendor
}}
>
{children}
</UserContext.Provider>
);
};
The code looks ok. Just make sure your component is wrapped in a <Router> context.

Categories