use next.js
update and set work without problems, but when I want to read using on, an error occurs, in the settings firebase checked for me read and write = true
import { getDatabase,ref,set,once,on,update,onChildAdded} from 'firebase/database';
const reference = ref(db, 'room/' + 'new');
// get support data from firebase
reference.on('value',function (snapshot) {
console.log("In Value");
console.log(snapshot.val());
}, function(error) {
console.error(error);
});
I get an error
reference.on is not a function at startSubmit
my firebase
There is a onValue() function in the new Modular SDK to listen for updates at the database reference. Try refactoring the code like this:
import { getDatabase, ref, onValue} from "firebase/database";
const reference = ref(db, 'room/' + 'new');
onValue(reference, (snapshot) => {
const data = snapshot.val();
console.log(data)
});
Checkout the documentation for more information.
I have config/firebase.ts:
import { initializeApp, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore'
const firebaseAdminApp = initializeApp({
credential: cert({
privateKey: process.env.NEXT_PUBLIC_FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'),
clientEmail: process.env.NEXT_PUBLIC_FIREBASE_SERVICE_EMAIL,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID
}),
databaseURL: `https://${process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID}.firebaseio.com`
});
const firestore = getFirestore(firebaseAdminApp);
export default firestore
and when trying to upsert, I have:
import firestore from "../config/firebaseAdmin";
const upsertInstance = async (instance: Instance) => {
const hashedUri = createHash('sha256').update(instance.uri).digest('hex')
const res = await firestore.doc(`instances/${hashedUri}`).set(instance);
return res
}
but I get:
Error: expected a function
What am I doing wrong?
Firebase Admin is not totally modular yet like the client SDK yet so you would have to use namespaced syntax. Admin SDK's Firestore instance won't work perfectly with client SDK functions. Try refactoring the code as shown below:
export const db = getFirestore(firebaseAdminApp);
import { db } from "../path/to/firebase"
const upsertInstance = async (instance: Instance) => {
const res = await db.doc(`instances/${instance.uri}`).set(instance);
return res;
}
Checkout the documentation for more information.
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 do we do this now:
const auth = getAuth(firebaseApp);
export async function updateUserEmail(email) {
try {
// let updatedUser = if need access
await auth.currentUser.updateEmail(email);
} catch (e) {
alert(e.message);
throw new Error();
}
}
updateEmail is no longer a method
You need to import updateEmail from the SDK this way now:
import firebase from "firebase/compat/app";
import { getAuth, onAuthStateChanged, updateEmail } from "firebase/auth";
// Initialize Firebase App
const app = firebase.initializeApp(firebaseConfig);
const auth = getAuth(app);
onAuthStateChanged(auth, (user) => {
console.log("Old Email", user.email);
updateEmail(user, "new#email.tld").then(() => {
console.log("email updated");
}).catch((e) => {
console.log(e);
});
});
Also you need to pass the user object itself in the updateEmail function so for testing purpose I've added the code in onAuthStateChanged but you can fetch the object or actually store it when page loads.
In a react-native project, I'm using both react-native-firebase and the firebase sdk.
react-native-firebase does not allow use of firebase storage to upload image blobs, which is why im using the vanilla Firebase javascript SDK to do this part. For distinction's sake, in my code & this post, im identifying the firebase javascript sdk as 'FIREBASE', and the react-native-firebase as 'firebase'.
I had to initialize my firebase app (even though react-native-firebase doesn't require this for its function, firebase does), App.js constructor & imports:
import * as React from 'react';
import AppNavigation from './src/navigation';
import { Provider } from 'react-redux';
import { store, persistor } from './src/store/index.js';
import firebase from 'firebase/app';
import { PersistGate } from 'redux-persist/integration/react';
export default class App extends React.Component {
constructor (props) {
super(props);
const firebaseConfig = {
apiKey: '{apiKey}',
authDomain: 'project-ID.firebaseapp.com',
databaseURL: 'https://project-ID.firebaseio.com',
projectId: 'project-ID',
storageBucket: 'project-ID.appspot.com',
messagingSenderId: '9999999999'
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
}
I implement firebase and FIREBASE in an action (firebase for auth/firestore, and FIREBASE for storage):
import * as types from '../actions/types';
import RNFetchBlob from 'rn-fetch-blob';
import firebase from 'react-native-firebase';
import * as FIREBASE from 'firebase/app';
import 'firebase/storage';
import { Platform } from 'react-native';
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
export const registerUser = (registration) => {
const { email, pass, username, img } = registration;
return (dispatch) => {
dispatch({ type: types.REGISTER_USER });
console.log('starting registration process...');
// check username is unique
firebase
.firestore()
.collection('users')
.where('username', '==', username)
.get()
.then((querySnapshot) => {
if (querySnapshot.empty !== true) {
// back to registration form
registrationFail(dispatch, 'Username already taken. Try again.');
console.log("Registrant's username already exists");
} else {
console.log('Registrants username is unique');
// continue with registration
firebase
.auth()
.createUserWithEmailAndPassword(email, pass)
.then((userCredential) => {
// successful user creation, now authenticated
// write to img storage
uploadImg(dispatch, img, userCredential.user.uid)
.then((imgUrl) => {
// on success, write to firestore
uploadImgSuccess(dispatch, 'Profile image upload successful...');
// write rest of data to firestore
firebase
.firestore()
.collection('users')
.add({
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
username: email,
uid: userCredential.user.uid,
profileImg: imgUrl,
email: email,
})
.catch((err) => {
console.log('Registration failed. Error: ' + err.message);
registrationFail(dispatch, err.message);
});
}
})
.catch((err) => {
// Image Profile NOT Uploaded
uploadImgFail(dispatch, err);
});
})
.catch((err) => {
// unsuccessful user creeation
registrationFail(dispatch, err.message);
});
}
})
.catch((err) => registrationFail(dispatch, err.message));
};
};
const uploadImg = async (dispatch, uri, uid, mime = 'image/png') => {
console.log('Starting image upload...');
dispatch({ type: types.UPLOAD_IMG, info: 'Uploading profile image...' });
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri;
let uploadBlob = null;
// let downloadPath = '';
const imageRef = FIREBASE.storage().ref(uid).child('profileImg');
fs
.readFile(uploadUri, 'base64')
.then((data) => {
return Blob.build(data, { type: `${mime};BASE64` });
})
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then((url) => {
console.log('Returning Download URL: ' + url);
uploadImgSuccess(dispatch, 'Image upload successful...');
})
.catch((err) => {
uploadImgFail(dispatch, 'Image upload failed: ' + JSON.stringify(err));
});
};
but when I go through uploadImg(), I get an error:
{
"code_": "storage/unauthorized",
"message":"Firebase Storage: User does not have permission to access 'someReference/someChild',
"serverResponse":{"Code":403, "message": "permission denied."}
}
Here is Firestore rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
Here is Storage rule:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I don't understand what's going on or why. The user is authenticated during react-native-firebase's createUserWithEmailAndPassword() and is even allowed to upload data to Firestore. My only guess is this possibly has something to do either with using both firebase & FIREBASE, or with the way i've setup firebase with FIREBASE. I've used both together in a previous test project and it worked successfully with the help of a forked project rn-fetch-blob (the maintained version of react-native-fetch-blob), however I had no security rules in place bc of testing, so...
Any ideas for solving this?
Yes, you have guessed it right, your FIREBASE instance is unaware of the auth being done by the firebase since the firebase handles the native aspects and FIREBASE is just a JS thing. so both of the instances have their own lives and their own prospects with own attributes to identify the user and provide authorization.
To resolve this, try authorizing the user either by the vanilla JS SDK or use the rn-firebase for the whole task.
I would recommend using react-native-firebase, it has good support for entire firebase stack.
https://rnfirebase.io/docs/v5.x.x/storage/reference/storage
EDIT:
Vanilla JS firebase SDK should not be used in mobile applications especially when it is native since firebase will treat the client as web client and going forward you will not be able to leverage all possible mobile things from firebase such as dynamic links, push notifications and analytics.
Hope this helps! Cheers!