So I am Building a Vue.js SPA using Rails 6 api as the backend and Vue-cli (legacy webpack template)
When I sign a user in, everything works fine, I can see the users details, it sets my setCurrentUser mutation and state, as soon as I click away from my dashboard, I loose all my user's state. the vue dev tool panel essentially shows everything reset back to false.
I am rather new to Vue / Vuex so this may be an oversight on my part.
My signin method to grab the current user:
methods: {
signin () {
let formData = new FormData()
formData.append('user[email]', this.user.email)
formData.append('user[password]', this.user.password)
this.$http.plain.post('/signin', formData, { emulateJSON: true })
.then(response => this.signinSuccessful(response))
.catch(error => this.signinFailed(error))
},
signinSuccessful (response) {
if (!response.data.csrf) {
this.signinFailed(response)
return
}
this.$http.plain.get('/api/v1/me')
.then(meResponse => {
this.$store.commit('setCurrentUser', { currentUser: meResponse.data, csrf: response.data.csrf })
this.error = ''
this.$router.replace('/dashboard')
this.flashMessage.show({
status: 'info',
title: 'Signed In',
message: 'Signin successful, welcome back!'
})
})
.catch(error => this.signinFailed(error))
},
signinFailed (error) {
this.user.error = (error.response && error.response.data && error.response.data.error)
this.$store.commit('unsetCurrentUser')
},
checkSignedIn () {
if (this.$store.state.signedIn) {
this.$router.replace('/dashboard')
}
}
}
This image shows the api call to signin completes and returns the user object.
This image shows the Vue Panel sets the currentUser state and has the user object
Now when I go to do a page refresh or move away from my dashboard, I loose everything that was in state.
So like I said I'm brand new to Vuex, I have tried to use Vue.set and $set on my mutations in store.js but this did not remedy the problem either..?
Here is my store.js file:
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
currentUser: {},
signedIn: false,
csrf: null
},
mutations: {
setCurrentUser (state, { currentUser, csrf }) {
state.currentUser = currentUser
state.signedIn = true
state.csrf = csrf
},
unsetCurrentUser (state) {
state.currentUser = {}
state.signedIn = false
state.csrf = null
},
refresh (state, csrf) {
state.signedIn = true
state.csrf = csrf
}
},
getters: {
isOwner (state) {
return state.currentUser && state.currentUser.role === 'owner'
},
isManager (state) {
return state.currentUser && state.currentUser.role === 'manager'
},
isAdmin (state) {
return state.currentUser && state.currentUser.role === 'admin'
},
isUser (state) {
return state.currentUser && state.currentUser.role === 'user'
},
isSignedIn (state) {
return state.signedIn === true
}
},
plugins: [
createPersistedState({
})
]
})
Any assistance here would be greatly appreciated!
Add plugins: [createPersistedState()], when creating store instance
export default new Vuex.Store({
plugins: [createPersistedState()],}
Related
i am getting the data from a config panel route setting it to the localstorage with vuex , storeJS:
const state = {
message: [],
// console.log(message);
sec: 0,
// other state
};
const getters = {
message: (state) => {
// console.log(this.state.message);
return state.message;
},
sec: (state) => {
return state.sec;
},
// other getters
};
const actions = {
setMessage: ({ commit, state }, inputs) => {
commit(
'SET_MESSAGE',
inputs.map((input) => input.message)
);
return state.message;
},
setSec: ({ commit, state }, newSecVal) => {
commit('SET_TIMEOUT', newSecVal);
return state.sec;
},
// other actions
};
const mutations = {
SET_MESSAGE: (state, newValue) => {
state.message = newValue;
localStorage.setItem('message', JSON.stringify(newValue)); ----->this
},
SET_TIMEOUT: (state, newSecVal) => {
state.sec = newSecVal;
localStorage.setItem('sec', JSON.stringify(newSecVal)); --->this
},
// other mutations
};
export default {
state,
getters,
actions,
mutations,
};
Now i am having a home route where i want to display this ,how can i access that?
I am getting the data (not the localstorage but the regular state data) with Mapgetters and i am using it like that:
computed: {
...mapGetters({
message: "message",
sec: "sec"
}),
how can i tell him that if there is nothing (when a page reloads ) to automaticcally get the data from localstorage.
This is my MOunted
mounted() {
this.$store.dispatch("SET_MESSAGE");
this.$store.dispatch("SET_SEC");
},
I will suggest you use this package to keep your state and local storage in sync vuex-persistedstate.
Alternatively, you can set your state like this.
const state = {
message: localStorage.getItem('message') || [],
// console.log(message);
sec: localStorage.getItem('sec') || '',
// other state
};
I'm trying to change the value of a state from false to true but it's not seeming to work. Below I will add my store, component that only gets the state, and the component that should update the state.
//Store
export const store = new Vuex.Store({
state: {
newComment: false,
status: ''
},
mutations: {
updateComments(state, payload) {
state.newComment = payload;
}
}
});
// Component that gets state
<template>
<div class="home">
<h1>{{newComment}}</h1>
<SelectedVideo v-bind:user="user" v-bind:video="videos[0]"/>
</div>
</template>
<script>
import axios from 'axios';
import SelectedVideo from '../components/SelectedVideo.component';
axios.defaults.withCredentials = true;
export default {
name: 'Home',
components: {
SelectedVideo
},
data() {
return {
videos: [],
user: null
}
},
computed: {
newComment() {
return this.$store.state.newComment
}
},
// Component I need to update state
methods: {
updateComments() {
this.$store.dispatch('updateComments', true);
}
},
async createComment(comment, video, user) {
try{
const res = await axios({
method: 'POST',
url: 'http://localhost:8000/api/v1/comments/',
data: {
comment,
video,
user
}
});
if (res.data.status === 'success') {
console.log(res);
// location.reload(true);
this.updateComments();
}
} catch(err) {
I'm successfully getting the state but updating seems to have no affect on state when I try to invoke the function to update.
First make a getter for using state data.
getters:{
get_newComment: state => state.newComment
}
Than implement this into your computed property.
computed: {
newComment() {
return this.$store.getters.get_newComment
}
}
After then use to "Commit" to commit some changes not "dispatch". Dispatch using for calling actions.
I have setup my routes.js file to import my state from my store. This is working as when I console.log(state) it outputs my store to console successfully:
I then define my route as below:
routes.js
import { state } from './store/store';
// import { mapState, mapGetters } from "vuex";
console.log(state)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
},
{
path: '/project/:id',
name: 'project',
component: Project,
props: true,
meta: {
requiresAuth: true,
},
children: [
{
path: 'module/:module',
name: 'module',
component: Tasks,
props: true,
children: [
{
path: 'task/:url',
name: 'task',
component: () => import(`./components/ProductServiceAnalysis/${$state.taskURL}.vue`),
props: true,
I am getting the error:
app.js:59653 [vue-router] Failed to resolve async component default: ReferenceError: state is not defined in relation to the second last line where I try to access the state.taskURL variable.
Why is this erroring? And how can I access my taskURL variable in my store from my Router?
If I am approaching this incorrectly then please offer suggestions.
This is my store.js:
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios'
Vue.use(Vuex);
axios.defaults.baseURL = 'http://buildmybusiness.test/api'
Vue.config.devtools = true;
export const state = {
token: localStorage.getItem('access_token') || null,
requiredTask: 'This is my current task',
currentModule: '1',
currentModuleName: 'Product & Service Analysis',
currentTask: '1',
modules:[],
tasks:[],
taskName:[],
actions:[],
userId: localStorage.getItem('loggedin_user') || null,
userName: localStorage.getItem('loggedin_username') || null,
projects:[],
currentProjectId: '',
currentProjectName: '',
taskURL: 'define-product-service'
}
export const store = new Vuex.Store({
state,
mutations: {
SET_MODULES: (state, payload) => {
state.modules = payload;
},
SET_TASKS: (state, tasks) => {
state.tasks = tasks;
},
SET_MODULE_TITLE: (state, moduleTitle) => {
state.currentModuleName = moduleTitle
},
SET_ACTIONS: (state, payload) => {
state.actions = payload;
},
RETRIEVE_TOKEN: (state, token) => {
state.token = token;
},
DESTROY_TOKEN: (state) => {
state.token = null;
},
SET_USERID: (state, userid) => {
state.userId = userid;
},
DESTROY_USERID: (state) => {
state.userId = null;
},
SET_USERNAME: (state, username) => {
state.userName = username;
},
DESTROY_USERNAME: (state) => {
state.userName = '';
},
SET_PROJECTS: (state, projects) => {
state.projects = projects;
},
DESTROY_PROJECTS: (state) => {
state.projects = [];
},
SET_PROJECT_ID: (state, projectId) => {
state.currentProjectId = projectId;
},
SET_PROJECT_NAME: (state, projectName) => {
state.currentProjectName = projectName;
},
SET_ACTION_URL: (state, taskURL) => {
state.taskURL = taskURL;
},
},
getters: {
loggedIn(state){
return state.token !== null;
},
SelectedTaskURL(state) {
return state.taskURL;
}
},
actions: {
setActionsURL(context, taskURL){
context.commit("SET_ACTION_URL", taskURL);
},
setProject(context, projectDetails){
const projectId = projectDetails.projectId;
const projectName = projectDetails.projectName;
context.commit("SET_PROJECT_ID", projectId);
context.commit("SET_PROJECT_NAME", projectName);
},
fetchProjects(context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token;
return axios.get('/project').then(response => {
const projectNames = response.data.map(project => project);
context.commit("SET_PROJECTS", projectNames);
});
},
getUserDetails(context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token;
return axios.get('/user').then(response => {
const userid = response.data.id
localStorage.setItem('loggedin_user', userid)
context.commit("SET_USERID", userid);
const username = response.data.name
localStorage.setItem('loggedin_username', username)
context.commit("SET_USERNAME", username);
});
},
register(context, data) {
return new Promise ((resolve, reject) => {
axios.post('/register', {
name: data.name,
email: data.email,
password: data.password,
})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error);
})
})
},
destroyToken(context){
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token
if (context.getters.loggedIn){
return new Promise ((resolve, reject) => {
axios.post('/logout')
.then(response => {
localStorage.removeItem('access_token')
context.commit("DESTROY_TOKEN")
context.commit("DESTROY_USERID")
context.commit("DESTROY_USERNAME")
context.commit("DESTROY_PROJECTS")
resolve(response)
})
.catch(error => {
localStorage.removeItem('access_token')
context.commit("DESTROY_TOKEN")
context.commit("DESTROY_USERID")
context.commit("DESTROY_USERNAME")
context.commit("DESTROY_PROJECTS")
reject(error);
})
})
}
},
loadModules(context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token
return axios.get('/modules').then(response => {
context.commit("SET_MODULES", response.data);
});
},
getTasks(context, moduleDetails){
var moduleTitle = moduleDetails.moduleName;
var moduleTitle = (moduleTitle === undefined) ? moduleTitle = 'Product & Service Analysis' : moduleTitle;
//console.log(moduleTitle);
var moduleId = moduleDetails.moduleId;
var moduleId = (moduleId === undefined) ? moduleId = 1 : moduleId;
return axios.get(`project/${context.state.currentProjectId}/module/${moduleId}`)
.then(response => {
context.commit("SET_TASKS", response.data);
context.commit("SET_MODULE_TITLE", moduleTitle);
});
},
loadTasks(context, tasks){
},
loadActions(context){
},
retrieveToken(context, credentials){
return new Promise ((resolve, reject) => {
axios.post('/login', {
username: credentials.username,
password: credentials.password,
})
.then(response => {
const token = response.data.access_token
localStorage.setItem('access_token', token)
context.commit("RETRIEVE_TOKEN", token)
resolve(response)
})
.catch(error => {
console.log(error);
reject(error);
})
})
},
}
});
my app.js
// main.js
require('./bootstrap');
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import VueAxios from 'vue-axios';
import axios from 'axios';
import routes from './routes';
import BootstrapVue from 'bootstrap-vue'
import { store } from './store/store';
import Vuex from 'vuex'
Vue.config.productionTip = false;
Vue.use(VueRouter);
Vue.use(VueAxios, axios);
Vue.use(BootstrapVue);
Vue.use(Vuex);
const router = new VueRouter({
store,
routes,
mode: 'history'
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.loggedIn) {
next({
name: 'login',
})
} else {
next()
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (store.getters.loggedIn) {
next({
name: 'dashboard',
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
new Vue({
store: store,
router,
render: h => h(App)
}).$mount('#app');
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';
If reference to #shazyriver:
I have done as you suggested. I have put a console.log(./components/ProductServiceAnalysis/${state.taskURL}.vue); before const routes = [ ... which correctly accesses the taskURL property and prints it to console. However, it still fails with a 'state undefined' when it tries to access the same property from within the route itself - even though it works when accessed outside the const routes = [:
See console log for detail
First of all, your configuration and all your imports are correct.
It's very interesting issue...I have researched it and can conclude that there is a kind of bug in transpilation process of webpack+babel. Let me explain:
If you check your bundle you can see that there is strange untranspiled concat expression in your dynamic import line, something like this: ("./".concat(state.taskURL,".vue")) - but state should be wrapped with webpack helpers but it wasn't...Looks like module resolving was skipped for import statement string interpolation.
The simplest solution is just assign imported module to some variable and use that variable in the import statement(I recommend to use fully configured store instead of state):
import { store } from './store/store';
let storeVar = store;
//...
//...below
component: () => import(`./components/ProductServiceAnalysis/${storeVar.state.taskURL}.vue`),
In this case module will be processed correctly by webpack.
P.S. I had created clean project with just webpack and tried to play with dynamic imports and they was resolved successfully...So I suppose that issue in another transpilation layer, maybe babel.
P.P.S. If my explanation is not enough clear please feel free to ask in comments.
You just need to import it like:
import store from './store/store.js'
Then you can use it like:
store.commit('increaseCounter')
Using NuxtJS (a VueJS framework), I’m trying to get a bunch of datas from a REST API in a layout template (which can’t use the classic fech() or asyncData() methods).
So I'm using vuex and the nuxtServerInit() action.
This way, I should be able to gather all the datas directly during the load of the app, regardless of the current page.
But I can’t get it to work.
Here’s my map.js file for the store:
import axios from 'axios'
const api = 'http://rest.api.localhost/spots'
export const state = () => ({
markers: null
})
export const mutations = {
init (state) {
axios.get(api)
.then((res) => {
state.markers = res.data
})
}
}
export const actions = {
init ({ commit }) {
commit('init')
}
}
And the index.js (that can fire the nuxtServerInit()):
export const state = () => {}
export const mutations = {}
export const actions = {
nuxtServerInit ({ commit }) {
// ??
console.log('test')
}
}
But I can’t get it to work. The doc says:
If you are using the Modules mode of the Vuex store, only the primary module (in store/index.js) will receive this action. You'll need to chain your module actions from there.
But I don’t know how I shall do this. How do I call an action defined in another module/file?
I tried to copy various example, but never got them to work ; this is the best I could come up with.
What did I missed? If needed, here’s the repo and the store folder
Thanks!
I ran into the same problem, a few weeks ago, and here is how I solved it:
======== CLASSIC MODE =========
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './modules/auth'
import auth from './modules/base'
Vue.use(Vuex)
export default () => {
return new Vuex.Store({
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user && req.session.token) {
commit('auth/SET_USER', req.session.user)
commit('auth/SET_TOKEN', req.session.token)
}
}
},
modules: {
auth,
base
}
})
}
store/modules/auth.js
const state = () => ({
user: null,
token: null
})
const getters = {
getToken (state) {
return state.token
},
getUser (state) {
return state.user
}
}
const mutations = {
SET_USER (state, user) {
state.user = user
},
SET_TOKEN (state, token) {
state.token = token
}
}
const actions = {
async register ({ commit }, { name, slug, email, password }) {
try {
const { data } = await this.$axios.post('/users', { name, slug, email, password })
commit('SET_USER', data)
} catch (err) {
commit('base/SET_ERROR', err.response.data.message, { root: true })
throw err
}
},
/* ... */
}
export default {
namespaced: true,
state,
getters,
mutations,
actions
}
Please notice the lines commit('base/SET_ERROR', err.response.data.message, { root: true }), which calls the mutation in another module (called base). And the namespaced: true option, which is required for this to work.
To learn more about namespacing in vuex modules, please refer to the documentation: https://vuex.vuejs.org/en/modules.html
======== MODULES MODE =========
The new 'modules mode' makes this much easier. You can have all the files in one folder and 'namespaced = true' is not required anymore.
Here is how the above files look in modules mode:
store/index.js
export const state = () => ({})
export const actions = {
async nuxtServerInit ({ commit }, { req }) {
if (req.session.user && req.session.token) {
commit('auth/SET_USER', req.session.user)
commit('auth/SET_TOKEN', req.session.token)
}
}
}
store/auth.js
const state = () => ({
user: null,
token: null
})
const getters = {
getUser (state) {
return state.user
},
getToken (state) {
return state.token
}
}
const mutations = {
SET_USER (state, user) {
state.user = user
},
SET_TOKEN (state, token) {
state.token = token
}
}
const actions = {
async register ({ commit }, { name, slug, email, password }) {
try {
const { data } = await this.$axios.post('/users', { name, slug, email, password })
commit('SET_USER', data)
} catch (err) {
commit('base/SET_ERROR', err.response.data.message, { root: true })
throw err
}
}
}
export default {
state,
getters,
mutations,
actions
}
To learn more about modules mode in nuxtjs, please refer to the documentation:
https://nuxtjs.org/guide/vuex-store/#modules-mode
When trying to check if a user is signed in via firebase.auth().currentUser like this:
if (firebase.auth().currentUser === null) {
console.log('User not signed in');
}
Whenever I refresh the page, or navigate around the above returns null (even though I have just logged in).
The weird thing is, that if I log
console.log(firebase.auth().currentUser) // This returns null
console.log(firebase.auth()) // Here I can inspect the object and currentUser exists...!
I don't really know what's going on here. I'm using React and Redux, but it shouldn't really matter I'd say.
Is there a small delay where the firebase initialises and you can't access the currentUser? If so, how can I see it in the log output of firebase.auth()?
This is a commonly asked question.
https://firebase.google.com/docs/auth/web/manage-users
You need to add an observer to onAuthStateChanged to detect the initial state and all subsequent state changes,
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
A simple way is to add a pending state.
Here is a react example using hooks:
// useAuth.ts
import { useState, useEffect } from 'react'
import { auth } from 'firebase'
export function useAuth() {
const [authState, setAuthState] = useState({
isSignedIn: false,
pending: true,
user: null,
})
useEffect(() => {
const unregisterAuthObserver = auth().onAuthStateChanged(user =>
setAuthState({ user, pending: false, isSignedIn: !!user })
)
return () => unregisterAuthObserver()
}, [])
return { auth, ...authState }
}
// SignIn.tsx
import React from 'react'
import { StyledFirebaseAuth } from 'react-firebaseui'
import { useAuth } from '../hooks'
export default function SignIn() {
const { pending, isSignedIn, user, auth } = useAuth()
const uiConfig = {
signInFlow: 'popup',
signInOptions: [
auth.GoogleAuthProvider.PROVIDER_ID,
auth.FacebookAuthProvider.PROVIDER_ID,
],
}
if (pending) {
return <h1>waiting...</h1>
}
if (!isSignedIn) {
return (
<div>
<h1>My App</h1>
<p>Please sign-in:</p>
<StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={auth()} />
</div>
)
}
return (
<div>
<h1>My App</h1>
<p>Welcome {user.displayName}! You are now signed-in!</p>
<a onClick={() => auth().signOut()}>Sign-out</a>
</div>
)
}
The best way to always have access to currentUser is to use vuex and vuex-persistedstate
//Configure firebase
firebase.initializeApp(firebaseConfig);
//When ever the user authentication state changes write the user to vuex.
firebase.auth().onAuthStateChanged((user) =>{
if(user){
store.dispatch('setUser', user);
}else{
store.dispatch('setUser', null);
}
});
The only issue above is that if the user presses refresh on the browser the vuex state will be thrown away and you have to wait for onAuthStateChange to fire again, hence why you get null when you try to access currentUser.
The secret to the above code working all the time is to use vuex-persisted state.
In your store.js file
import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase/app'
Vue.use(Vuex)
import createPersistedState from "vuex-persistedstate";
export default new Vuex.Store({
plugins: [createPersistedState()],
state: {
user: null
},
getters:{
getUser: state => {
return state.user;
}
},
mutations: {
setUser(state, user){
state.user = user;
}
},
actions: {
setUser(context, user){
context.commit('setUser', user);
},
signIn(){
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function (result) {
})
},
signOut(){
firebase.auth().signOut();
}
}
})
You can now protect routes in your router as in the code example below.
import Vue from 'vue'
import Router from 'vue-router'
import Home from '#/components/Home'
import Search from '#/components/Search/Search'
import CreateFishingSite from '#/components/FishingSites/CreateFishingSite'
Vue.use(Router);
import store from './store'
import firebase from 'firebase'
let router = new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/search/:type',
name: 'Search',
component: Search
},
{
path: '/fishingsite/create',
name: 'CreateFishingSite',
component: CreateFishingSite,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach(async (to, from, next)=>{
let currentUser = store.state.user;
console.log(currentUser);
let requriesAuth = to.matched.some(record => record.meta.requiresAuth);
if(requriesAuth && !currentUser){
await store.dispatch('signIn');
next('/')
}else{
next()
}
})
If you are looking for a copy and paste Auth route for react with firebase:
const AuthRoute = ({ component: Component, ...rest }) => {
const [authenticated, setAuthenticated] = useState(false)
const [loadingAuth, setLoadingAuth] = useState(true)
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
setAuthenticated(true)
} else {
setAuthenticated(false)
}
setLoadingAuth(false)
})
}, [])
return loadingAuth ? 'loading...' : (
<Route
{...rest}
render={props =>
authenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/user/login' }} />
)}
/>
)
}
Promise-wise, there are three options:
UPDATE: 11/26/22
For Firebase 9+, you could do:
Note: (this.auth) is the Auth object and depends on your framework.
const user1 = await firstValueFrom(authState(this.afa));
const user2 = await firstValueFrom(
new Observable(observer => onAuthStateChanged(this.afa, observer))
);
const user3 = this.afa.currentUser;
// best option
const user1 = await new Promise((resolve: any, reject: any) =>
firebase.auth().onAuthStateChanged((user: any) =>
resolve(user), (e: any) => reject(e)));
console.log(user1);
// sometimes does not display correctly when logging out
const user2 = await firebase.auth().authState.pipe(first()).toPromise();
console.log(user2);
// technically has a 3rd state of 'unknown' before login state is checked
const user3 = await firebase.auth().currentUser;
console.log(user3);
// On component load.
componentDidMount = () => this.getAuthStatus();
// Get firebase auth status.
getAuthStatus = () => {
firebase.auth().onAuthStateChanged((resp) => {
// Pass response to a call back func to update state
this.updateUserState(resp);
});
}
// update state
updateUserState = (resp) => {
this.setState({
user: resp
})
}
// Now you can validate anywhere within the component status of a user
if (this.state.user) { /*logged in*/}
Best approach for this is to use a promise and only instantiate the router after the response, something along the lines of:
store.dispatch('userModule/checkAuth').then(() => {
// whatever code you use to first initialise your router, add it in here, for example
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
})
inside the checkAuth action is where you would have your promise, like so:
checkAuth ({ commit }) {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged(async (_user) => {
if (_user) {
commit('setUser', _user)
} else {
commit('setUser', null)
}
console.log('current user in checkAuth action:', _user)
resolve(true)
})
})
h/t to aaron k saunders - the source of this solution for me.
If you'd like the user to access to a certain page only if he is authenticated and to redirect to the home page if he is not, the following codes might help:
in React:
make a component with the following code:
import { onAuthStateChanged } from "#firebase/auth";
import { Route, Redirect } from "react-router-dom";
import { auth } from "../firebase/config";
import { useState, useEffect } from "react";
const GuardedRoute = ({ component, path }) => {
const [authenticated, setAuthenticated] = useState(false);
const [authCompleted, setAuthCompleted] = useState(false);
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setAuthenticated(true);
} else {
setAuthenticated(false);
}
setAuthCompleted(true);
});
}, []);
return authCompleted ? (
authenticated ? (
<Route path={path} component={component} />
) : (
<Redirect to="/" />
)
) : (
""
);
};
export default GuardedRoute;
and in app.js use:
import RouterPage from "./pages/RouterPage";
<GuardedRoute path="/router-page" component={RouterPage} />
in Vue:
at the router file use:
const guardSuccess = (to, from, next) => {
let gUser = auth.currentUser
if (gUser) {
next()
} else {
next({ name: "Home" })
}
}
and in the routes of the page you want to restrict access to add:
{
path: "/router-page",
name: "routerPage",
component: () => import("../views/routerPage.vue"),
beforeEnter: guardSuccess
}
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
var user = firebase.auth().currentUser;
if(user != null){
var io=user.uid;
window.alert("success "+io);
}
} else {
// No user is signed in.
Window.reload();
}
});
first check if user exist then get it id by
firebase.auth().currentUser.uid