I'm fairly new to Vue and this is the second tutorial I'm following, which integrates firebase backend with Vue. But the tutorial is using Vue 2 and also an older version of firebase, so I thought I could try to do it with Vue 3 and the new Firebase version.
The resources on the firebase 9.0.1 seems to be fairly limited with regards to implementation with Vue at least. This is what I found from the firebase documentation regarding the signInAnonymously
import { getAuth, signInAnonymously } from "firebase/auth";
const auth = getAuth();
signInAnonymously(auth)
.then(() => {
// Signed in..
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
From what I understand, firebase 9.0.1 is an import only what you use style? so If I want to use the getAuth and signInAnonymously methods from the firebase/auth, I would do
import { getAuth, signInAnonymously } from 'firebase/auth';
But I am a bit confused as to how to use the methods in my .Vue file
so what I did in my firebase.js file was
export const auth = getAuth();
export {signInAnonymously};
then in my Login.vue file, i did
import { auth, signInAnonymously } from '../firebase'
export default {
data() {
return { auth }
},
methods: {
signInAnonymously
}
}
and I have a button that when clicked triggers the signInAnonymously, which is written like so
<button class="button" #click="signInAnonymously(auth)">Sign In</button>
What I have written seems to work, but I find it a bit convoluted/confusing and want to know
am I doing this correctly or is there a shorter/neater way to write the code?
what happens if I want to modify the signInAnonymously method as shown in the firebase documentation, i.e. adding those signInAnonymously(auth).then(() => {}), because if i were to add the arguments for the signInAnonymously in my export default like below, it doesn't recognize it as the exported method from my firebase.js file?
export default {
...,
methods: {
signInAnonymously(auth) {
...
}
}
Try creating a custom method and using signInAnonymously() within that as shown below:
import { auth } from '../firebase'
import { signInAnonymously } from 'firebase/auth'
// can be imported directly in Login.vue ^^
export default {
methods: {
anonymousLogin() {
// Directly pass 'auth' in this method
signInAnonymously(auth)
.then(() => {
// Signed in..
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
},
},
};
Then use this custom method in #click event:
<button class="button" type="button" #click="anonymousLogin">Sign In</button>
Related
Currently I'm using tailwind css and headlessui for a few components and firebase.
Now I would like to use quasar but the boot files are very mysterious to me.
Currently I manage firebase with config.js, main.js and pinia store.
I replaced my old config.js file with a firebase.js boot file as recommended by Quasar and it seems to work. (but I don't really know if it's good practice)
import { boot } from 'quasar/wrappers'
import { initializeApp } from 'firebase/app'
import { getFirestore } from 'firebase/firestore'
import { getAuth } from 'firebase/auth'
const firebaseConfig = {
apiKey: 'xxxxxxxxxxxxxx',
authDomain: 'xxxxxxxxxxxxxx',
projectId: 'xxxxxxxxxxxxxx',
storageBucket: 'xxxxxxxxxxxxxx',
messagingSenderId: 'xxxxxxxxxxxxxx',
appId: '1:xxxxxxxxxxxxxx'
}
// Init firebase
initializeApp(firebaseConfig)
// Init services
const db = getFirestore()
const auth = getAuth()
export { db, auth }
// "async" is optional;
// more info on params: https://v2.quasar.dev/quasar-cli/boot-files
export default boot(async (/* { app, router, ... } */) => {
// something to do
})
But I don't know what to do with the old mains.js file which is no longer available in Quasar. In main.js there is the following code:
import { createApp, markRaw } from 'vue'
import router from './router/router'
import { createPinia } from 'pinia'
import App from './App.vue'
// firebase
import { auth } from './firebase/config'
import { onAuthStateChanged } from 'firebase/auth'
import './input.pcss'
let app
onAuthStateChanged(auth, () => {
if (!app) {
app = createApp(App)
.use(
createPinia().use(({ store }) => {
store.$router = markRaw(router)
})
)
.use(router)
.mount('#app')
}
})
What should I do with the code above in particular with the onAuthStateChanged function?
Thanks for your help
I've found a solution for this that is suitable for my purposes. For me the requirements were:
Make sure auth is initialized on a refresh, before rendering.
Make sure any data required for the app is also initialized, before rendering.
Detect log-in, log-out, and time outs and act accordingly.
I haven't tested time outs yet but basically I solved this with the following flow.
In your router/index.js file, add a before each function, that checks to see if a listener is active, and calls a store function to create it if not.
Router.beforeEach(async (to, from, next) => {
// Access a store where you check if the auth changes are being handled
const storeAuth = useAuth()
if (!storeAuth.handlingAuth) {
await storeAuth.handleAuth()
}
// Redirects as necessary using to.path and next
next()
})
In the auth store, make a function that returns a promise to await in the beforeEach. Something like:
async handleAuth() {
const auth = getAuth()
return new Promise((resolve) => {
let initialLoad = true
auth.onAuthStateChanged(async (user) => {
if (user) {
await this.initializeUserData()
} else {
await this.clearUserData()
}
// If it is not initial load, use the router to push
// depending on whether the user exists.
// if (user && !initialLoad) this.router.push('/members')
// This would detect a login and go to the members section.
// If it is the initial load, resolve the promise
// so the router proceeds
if (initialLoad) {
initialLoad = false
this.handlingAuth = true
resolve()
}
})
})
}
Don't make the mistake of using useRouter() in the store. useRouter() is only for use in the setup function, or <script setup>. What you need to do is add the router as a plugin to Pinia. So in your stores/index.js import your router, then add this:
pinia.use(({ store }) => { store.router = markRaw(router) })
That way you can use this.router.push() in your store modules.
This might seem a bit messy because of redirects in both the navigation guard and the store action but this seems like the easiest way to get it to load the required data from both refresh and login while only using onAuthStateChanged in one place.
In summary it works like this:
When refreshed or entering a url manually, the app awaits the first state change, and any necessary loading.
Then in the nav guard, you can check whatever store variables you need to check your user login state, and redirect. Like back to the login page, if the user happened to enter a url for a members-only section.
Subsequent navigations (non-refresh) see that the auth handling is already set up, so it is ignored.
When a separate function triggers login or logout, we can see that it is not the initialLoad, and do any other redirects at that point.
I am a beginner at React.js. I was following a tutorial to make a login authentication. I am getting this error (TypeError: fire__WEBPACK_IMPORTED_MODULE_1_.default.auth is not a function) from this part of the code:
`
const authListener = () => {
fire.auth().onAuthStateChanged((user) => {
if (user) {
clearInputs();
setUser(user);
} else {
setUser("");
}
})
};
`
I've already searched every forum, topic, or Youtube video and still can't find the answer. Can someone tell me where the problem is and how to fix it? Appreciate everything.
If you are using the Modular SDK v9.0.0 then try refactoring your code like this:
import { initializeApp } from "firebase/app"
import { getAuth, onAuthStateChanged } from "firebase/auth"
const app = initializeApp(app)
const auth = getAuth(app)
const authListener = () => {
onAuthStateChanged(auth, (user) => {
if (user) {
console.log(user)
}
})
}
If you want to use the older namespaced syntax (firebase.auth()) then change your imports to compat version:
import firebase from "firebase/comapt/app"
import "firebase/compat/auth"
You can read more about upgrading to modular SDK in the documentation.
I'm trying to use google sign using firebase in the Vue framework. I don't know what the error is this can anyone help me with this.
vue.runtime.esm.js?2b0e:1888 TypeError: _firebase_js__WEBPACK_IMPORTED_MODULE_2__.fb.auth.GoogleAuthProvider is not a constructor
at VueComponent.socialLogin (Signin.vue?3d55:76)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6917)
this is my code
firebase.js
import firebase from "firebase";
var firebaseConfig = {
config
};
const fb=firebase.initializeApp(firebaseConfig);
export { fb };
Sign in.vue
<script>
import { fb } from "../firebase.js";
export default {
name: "Signin",
components: {},
data() {
return {
};
},
methods: {
socialLogin() {
const provider = new fb.auth.GoogleAuthProvider();
fb.auth().signInWithPopup(provider).then((result) => {
this.$router.replace('home');
}).catch((err) => {
alert('Oops. ' + err.message)
});
}
}
};
</script>
The auth property (not the auth() function) is available on the static firebase object, not your firebase app.
You want something more like this
import firebase from "firebase/app"
import "firebase/auth" // 👈 this could also be in your `firebase.js` file
const provider = new firebase.auth.GoogleAuthProvider()
I am trying to use Firebase Authentication on my Next.js website. For some reason, when I press the sign up button, nothing happens and no errors are logged. It just refreshes the page. It doesn't even set any cookies or create a user.
Here are my two files related to authentication:
utils/authProvider.js:
import firebase from 'firebase/app';
import 'firebase/auth';
if(!firebase.apps.length) {
firebase.initializeApp({
// config
});
}
const auth = firebase.auth();
module.exports = { auth };
pages/signup.js:
import { useState } from 'react'
import { LockClosedIcon } from '#heroicons/react/solid'
import { auth } from '../utils/authProvider'
export default function CreateAccount() {
const [emailField, setEmailField] = useState('');
const [passwordField, setPasswordField] = useState('');
// emailField and passwordField are set correctly, I used console.log to test it
const createAccount = () => {
// this event does get triggered, I used console.log to test it
auth.createUserWithEmailAndPassword(emailField, passwordField)
.then((userCredential) => {
window.location.replace('/');
console.log('logged in!');
}).catch((error) => {
console.error(error);
});
}
Edit: After experimenting some more, I saw that the request to https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser never gets completed. It just shows as red in the network traffic tab of Chrome dev tools. Any reason why this might happen?
Thanks in advance.
i'm french, sorry for my little english.
I've a problem with Reactjs and Firebase, an error when i want connect with Facebook. I look tutorial in Udemy platform. This is a video for learn React
REBASE: The Firebase endpoint you are trying to listen to must be a string. Instead, got undefined
Parts of code Admin.js :
import React, { Component } from 'react'
import AjouterRecette from './AjouterRecette'
import AdminForm from './AdminForm'
import Login from './Login'
import firebase from 'firebase/app'
import 'firebase/auth'
import base, { firebaseApp } from '../base'
class Admin extends Component {
state = {
uid: null,
chef: null
}
componentDidMount () {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.handleAuth({ user })
}
})
}
handleAuth = async authData => {
console.log(authData)
const box = await base.fetch(this.props.pseudo, { context: this })
if (!box.chef) {
await base.post(`${this.props.pseudo}/chef`, {
data: authData.user.uid
})
}
this.setState({
uid: authData.user.uid,
chef: box.chef || authData.user.uid
})
}
authenticate = () => {
const authProvider = new firebase.auth.FacebookAuthProvider()
firebaseApp
.auth()
.signInWithPopup(authProvider)
.then(this.handleAuth)
}
...
export default Admin
Thank's
Have a good day.
......................................................................................................................................................................................................................................................................................................................................................................................................
I've got exactly the same problem, probably because I follow the same training as you.
Your error is here :
const box = await base.fetch(this.props.pseudo, { context: this })
because this.props.pseudo is null.
in app.js, in the admin component, write
pseudo={this.props.match.params.pseudo}
and not
pseudo={this.state.pseudo}
and that shoudl work.
regards