Firebase Realtime data is only available after saving the edited source file? - javascript

I'm relatively new to RN / Javascript, so this might be a rookie mistake - strangely I couldn't find anything close to it on my research.
My setup: I'm developing a RN app with Expo and I'm using the Expo Go app to see any changes.
Since I want to enable cloud services, I'm using the Firebase Realtime database with the official packages in my app. So far, so good.
My issue: Every time I start the developement server (npm start) or reload the app with the 'r' shortcut on my Accounts screen (basic screen displaying the names of the accounts the user created), see attached screenshot, the app refuses to load the data from Realtime - instead I'm greeted with a 'undefined is not an object (evaluating 'obj['accounts']'). Once I hit 'STRG + S' on my keyboard in any file opened, the Expo Go app refreshes and the data is somehow found.
If anyone could help me with this issue, you would surely save my day. :)
CODE
My data is loaded from here (dataHandler.js):
// auth stuff
import { Auth, getAuth } from "firebase/auth";
// database stuff
import { db } from "./firebase";
import { get, onValue, ref } from 'firebase/database'
// more auth stuff
const auth = getAuth()
const userID = auth.currentUser?.uid;
// database Path for retrieving data
const databasePath = userID
export var cachedData = {};
// Gets data from the firebase server, set's it to a local value
export function getData() {
return onValue(ref(db, databasePath), querySnapshot => {
let data = querySnapshot.val() || {};
let downloadedData = {...data};
// set data to a public var
cachedData = downloadedData;
console.log('DEBUG: Data loaded from the server')
})
}
My account data is then loaded from here (accountData.js):
// load the data from dataHandler.js
import { cachedData } from "./dataHandler";
import { getAuth } from "firebase/auth";
const auth = getAuth()
const userID = auth.currentUser?.uid;
export function getAccountData() {
console.log('accountData receives = ', cachedData)
let obj = cachedData[userID];
let accounts = obj['accounts'];
console.log('getAccountData returns: ', accounts)
return accounts;
}
I'm calling the files here:
// experimental stuff
import { getData } from '../../core/dataHandler';
import { getAccountData } from '../../core/accountData'
const Accounts = () => {
// Downloads data on the app start
getData();
// load the data for the account
const accounts = getAccountData()
console.log('accountData = ', accounts)
const accountKeys = Object.keys(accounts)
const [ accountName, setAccountName ] = useState('')
return( <SomeView /> )
}

Related

Does AWS Javascript SDK v3 automatically read credentials from local config?

I'm looking at this page https://docs.aws.amazon.com/sdk-for-javascript... and it seems to imply that the SDK will look at ~/.aws/credentials and take the [default] profile if there is no AWS_PROFILE environment var.
I'm running a NextJS app on my local machine trying to list S3 buckets, getting Error: Credential is missing.
I would really love not to have to specify the creds in env vars as I'll be deploying the app to ECS later where it will use an IAM Role for access.
Here's my code:
import { ListBucketsCommand } from '#aws-sdk/client-s3';
import React, { useEffect } from 'react';
import { s3Client } from '../lib/s3Client';
const S3Buckets = () => {
useEffect(() => {
async function getS3Buckets() {
const input = {};
const command = new ListBucketsCommand(input);
const res = await s3Client.send(command);
console.log(res);
}
getS3Buckets();
}, []);
return <div>{/* S3 Buckets eventually listed here */}</div>;
};
export default S3Buckets;
with the s3Client helper as below:
import { S3Client } from '#aws-sdk/client-s3';
export const s3Client = new S3Client({ region: process.env.AWS_REGION });

Uncaught Error: Service database is not available firebase javascript

I am trying to access my realtime database in firebase but it shows me this error Uncaught Error: Service database is not available. I have searched for what this could posabbly mean but I couldn't find anything useful or a solution.
Here is my code:
window.addPerson = addPerson;
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const userVar = urlParams.get('user')
const userVarSplitted = userVar.split('#')
const userVarFormatted = userVarSplitted[0] + ":" + userVarSplitted[1]
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.4/firebase-app.js";
import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.6.4/firebase-analytics.js";
import { getDatabase, ref, set } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-database.js";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {MY FIREBASE CONFIG};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
if (app.length === 0) {
console.log("no firebas app")
}else{
console.log("initialized")
}
const analytics = getAnalytics(app);
const database = getDatabase(app);
function addPerson() {
set(ref(database, "verified/" + userVarFormatted), {
name: userVarSplitted[0],
discriminator: userVarSplitted[1]
});
console.log("added")
PS: The script type is set to modular.
Do you know what the error means and what is happening?
You're using difference versions of the Firebase SDKs. I'd update the database import to version 9.6.4 too, so that the all Firebase SDK versions are the same.

Cannot import Firebase Firestore Colletion

I'm trying to call a Firestore Colletion in my next app, here is the error that I get when running the app:
FirebaseError: Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).
Here is my firebase.js code:
import firebase from 'firebase/app';
import "firebase/firestore"
const firebaseConfig = {};
export const getPosts = async () => {
firebase.initializeApp(firebaseConfig);
const posts = await firebase.firestore().collection("articles").then((snapshot) => {
const snapshotVal = snapshot.val();
const result = [];
for (var slug in snapshotVal) {
const post = snapshotVal[slug];
result.push(post);
}
return result.reverse();
});
return posts
};
Because you keep trying to initialize a new firebase app every time you getPosts, so you should check first if there isn't a firebase app before initializeApp,
try something like this before getPosts function:
var firebase_app;
if (!firebase.apps.length) {
firebase_app = firebase.initializeApp(firebaseConfig);
} else {
firebase_app = firebase.app(); // if already initialized, use that one
}

How to fix firebase database initialised multiple times due to React SSR initialised database and cloud function firebase initialised database?

I have updated the question as found the root cause of the issue.
As I have hosted my React SSR app which uses firebase database in the client serving by one of the cloud function named app throwing an error of Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.. When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo?
ORIGINAL Question: Why firebase cloud function throwing an error of 'The default Firebase app does not exist.'?
So I am trying out firebase function for the first time. admin.messaging() throwing me the following error. Help me figure out why?
If I look at the console I get results till console.log('deviceToken', deviceToken);
so whats wrong in const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.updateUnreadCount = functions.database.ref('/chats/{chatId}/{messageId}')
.onCreate(async(snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const adminApp = admin.initializeApp(appOptions, 'app');
const { message, senderId, receiverUid } = snap.val();
console.log(message, senderId, receiverUid);
console.log('------------------------');
const deleteApp = () => adminApp.delete().catch(() => null);
try {
const db = adminApp.database();
const reciverUserRef = await db.ref(`users/${receiverUid}/contacts/${senderId}/`);
console.log('reciverUserRef', reciverUserRef);
const deviceTokenSnapshot = await reciverUserRef.child('deviceToken').once('value');
const deviceToken = await deviceTokenSnapshot.val();
console.log('deviceToken', deviceToken);
const payload = {
notification: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
}
};
const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);
console.log('Successfully sent message: ', JSON.stringify(messageDone));
return deleteApp().then(() => res);
} catch (err) {
console.log('error', err);
return deleteApp().then(() => Promise.reject(err));
}
});
Update1: According to this https://firebase.google.com/docs/cloud-messaging/send-message#send_to_a_topic, admin.messaging().sendToDevice(deviceToken, payload) APIs are only available in the Admin Node.js SDK?
So switched to
const payload = {
data: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
},
token: deviceToken
};
const messageDone = await admin.messaging().send(payload);
Which is not working either. Getting an error Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services. Any lead will be helpful.
EDIT: Finally got the function working.
My index.js is exporting to functions, follwoing
exports.app = functions.https.onRequest(app); //React SSR
exports.updateChat = functions.database.ref('/chats/{chatId}/{messageId}').onCreate(updateChat);
exports.app is a react ssr function, which I am using to host my site. This uses database too. and throwing error of multiple database instance.
When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo? Any suggestions, please?
You can initialise db outside export function.
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(appOptions, 'app')
//continue code
Update:
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(options);
async function initialize(options, apps = 'app') {
try {
const defaultApp = adminApp.name
if(defaultApp) {
const adminApp1 = admin.initializeApp(apps);
}else {
const adminApp1 = admin.initializeApp(options, apps);
}
}catch(err) {
console.error(err);
}
}
Modify this snippet as per your need and try it out
It abstracts initialize of app in another function. Just call this function at appropriate place in your code.

How to retrieve Firebase data using firebaseServer?

I created an app with Firebase authentication using Next.js' starter and setup the Firebase authentication and database. I can run the app just fine (log in and add messages).
Then I noticed it wasn't SSR'ing the Firebase data:
export default class Index extends Component {
static async getInitialProps({ req, query }) {
const user = req && req.session ? req.session.decodedToken : null;
// don't fetch anything from firebase if the user is not found
// const snap = user && await req.firebaseServer.database().ref('messages').once('value')
// const messages = snap && snap.val()
const messages = null;
return { user, messages };
}
I uncommented the code to see if I could SSR everything:
export default class Index extends Component {
static async getInitialProps({ req, query }) {
const user = req && req.session ? req.session.decodedToken : null;
// don't fetch anything from firebase if the user is not found
const snap =
user &&
(await req.firebaseServer
.database()
.ref("messages")
.once("value"));
const messages = snap && snap.val();
// const messages = null;
return { user, messages };
}
The user and snap have values but snap.val() is null.
How can I retrieve the messages via firebaseServer?
If it's any help, here's the whole file.
firebaseServer.database() === Realtime Database
The documents where being added to Cloud Firestore, not Realtime Database.
This pulls the documents from Cloud Firestore:
static async getInitialProps({ req, query }) {
const user = req && req.session ? req.session.decodedToken : null;
const snap =
user &&
(await req.firebaseServer
.firestore()
.collection("messages")
.get());
const messages = snap && snap.docs.map(d => d.data());
return { user, messages };
}

Categories

Resources