I am using vuex in nuxt and I get user data after user login, and store the data in vuex.
When I display the data in another page as computed property with getters, everything works fine and it displays user data except for img tag.
When I try to display user icon with url which is stored in vuex, it works for the first time, but when refresh the page, it gets the data before the user data is stored for some reason...( but the another data still renders user data properly) and of course, icon does not render.
Plus, if I just display the url of icon from vuex as strings in div, it shows icon url correctly even after refreshing the page... but not src in img tag...
I think I have a same problem as this question: Linking to images referenced in vuex store in Vue.js
and one of the answer says
:src='student.image' (v-binding) is executed at runtime, but webpack aliases work in compile time. So you have to wrap the aliased file path in require.
{
id: 1,
name: 'Advik',
age: '19',
studying: 'Physiotherapy',
image: require('~#/assets/images/students/advik-1.png')
}
so, I would like to use require in src but icon is rendered by url not by module, so I do not know how to solve this problem. How can I make icon render after refreshing the page as well?
This is my vuex,
//---------this is default state data--------------
export const state = () => ({
user: {
email: 'default',
id: 'default',
last_name: 'default',
name: 'name',
picture: 'picture',
provider: 'default',
},
}
// -------this is to set user and token in store and local storage-------
export const mutations = {
setUser(state, authData) {
const now = new Date()
const expirationDate = now.getTime() + 36000000
localStorage.setItem('token', authData.token)
localStorage.setItem('user', JSON.stringify(authData.user))
localStorage.setItem('expirationDate', expirationDate)
state.idToken = authData.token
state.user = authData.user
},
}
//---------this is to get userdata and fire mutation to set data ---------
export const actions = {
GetUserInfo({ commit }, token) {
this.$axios
.get('/auth/user/', {
headers: { Authorization: `Bearer ${token}` },
})
.then((res) => {
console.log(res)
const user = {
email: res.data.email,
id: res.data.id,
last_name: res.data.last_name,
name: res.data.name,
picture: res.data.picture,
provider: res.data.provider,
}
return user
})
.then((user) => {
commit('setUser', { token, user })
})
},
}
and this is index.vue where I am trying to display the user info.
<template>
<div>
<div>{{ userAvatar }}</div> //this displays picture url first time and after refreshes it as well.
<img class="avatar" :src="userAvatar" alt="" /> //this displays icon with picture url first time and, after I refresh it, userAvatar renders as "picture" which was the default data of state.
</div>
</template>
export default {
computed: {
userAvatar() {
const user = this.$store.getters['authentication/getUserInfo']
console.log(user) //even after refresh it, still console the user data I got.
return user.picture
},
},
}
Thanks a lot!
Related
I'm new to Vue / web development, ever since I started i've had a good amount of fun but now i'm stuck.
Currently I am creating an admin dashboard with Firebase authentication. Everything seems to work like it should but there is one thing that I still don't understand.
In the Vue Router I have all the different routes set up and the dashboard is inaccessible (if not logged in to Firebase).
This is my Router Guard:
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/register",
name: "Register",
component: Register,
},
{
path: "/login",
name: "Login",
component: Login,
},
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true,
},
},
];
router.beforeEach((to) => {
//If route requires authentication
if (to.matched.some((rec) => rec.meta.requiresAuth)) {
//Check firebase user
auth.onAuthStateChanged((user) => {
console.log(user);
//If the user object does not exist then redirect to the /Login page
if (!user) {
router.push("/login");
}
});
}
});
If I now try to open localhost:8080/dashboard it shows the dashboard for a split second and then hops to the /login page.
If also tried it with next({name: 'Login'}) but for some reason I keep getting white pages when I use next().
Hope someone can help me.
Thanks :)
The problem is that instead of checking for a logged-in user you are adding an "event listener" auth.onAuthStateChanged.. it fires async when the authentication state changes. However you need a sync check here. The best would be to use vuex and store your user in a global state. Though if you don't use vuex at all and you need your user only here, then probably a "local" user var in the router would also work.. something like this:
let user = null
auth.onAuthStateChanged(u => {
console.log(u)
if (u) {
user = u
} else {
user = null
}
})
router.beforeEach(to => {
if (to.matched.some(rec => rec.meta.requiresAuth)) {
//Check firebase user
if (!user) {
router.push("/login");
}
}
})
It's just a concept, but it should work.. let me know :)
Hey guys i am using React Hooks with redux, so what i want is lets say user need a signup on my website, so after posting his details i am sending back status :200 and if it has status:200 i am updating a state value in my userReducer like say "status" to true (which initially was false) and based on this boolean value i am showing a modal to user with the message. So code goes like
Actions.js
export const userRegisterAction = (data: any) => async (dispatch: any) => {
console.log(data);
axios.post("http://localhost:4000/register_user", data).then((res) => {
console.log("hittinh server");
console.log(res.data);
if (res.data.status == 200) {
dispatch({
type: USER_REGISTRATION_SUCCESS,
payload: res.data,
});
} else {
dispatch(errorActions());
}
});
};
Reducer.js
case USER_REGISTRATION_SUCCESS:
return {
...state,
status: true,
info: action.payload.doc.ops[0],
};
and then in my component
const user = useSelector((state: RootState) => {
console.log(state.user.info);
console.log(state.error.iserror);
return { user: state.user };
});
<IonAlert
isOpen={user.user.status == true}
cssClass="my-custom-class"
header={"User Registered!"}
backdropDismiss={false}
// subHeader={'User Registered !'}
message={"You have been registered successfully."}
// buttons={["OK"]}
buttons={[
{
text: "OK",
handler: () => {
console.log("Confirm Okay");
redirect();
},
},
]}
/>
Note. I am using redux persist and this reducer needs to be persisted for future purpose as i am gonna use this wherever i need user related task like if he needs to change password i will pick up the email from my user reducer so it doesnt gets lost on refresh
NOW COMING TO THE ISSUE, as my reducer state is persisted once the "status" is true if user wishes to signup from another account as soon as he goes to signup page he will again see the result of "ionAlert" as it will match the condition status==true , so what i am doing is on every unmount i am dispatching action which sets "status" to false, although this works fine, but i wanna know is this the correct approach , how are you all dealing with this stuff ??
I am trying create a to fetch data from the server and show them to the user. But the issue is that nothing apart from the dummy information is displayed.
Basically there are two scenarios:
1. Navigating to the page from some other link (This works as expected)
Explanation: Such as going from http://localhost:3000/ to http://localhost:3000/assignments/explore and it renders all the fetched contents as expected.
Vue plugin ss
2. Entering the page directly through the url or press refresh
Explanation: By directly typing http://localhost:3000/assignments/explore in the url nothing is displayed apart from the dummy card
Vue plugin ss
As you can see the length of the assignment state is 1 instead of 3 and the vuex action saveAssignments is also missing in this case
Template tag in explore.vue
...
<div v-for="assignment in assignments" :key="assignment._id">
<Card :assignment="assignment"></Card>
</div>
...
Script Tag in explore.vue
fetch() {
this.$store.dispatch('assignment/fetchAssignment')
},
computed: {
assignments() {
return this.$store.state.assignment.assignments
},
},
assignment.js //Vuex Store
export const state = () => ({
assignments: [ //dummy data
{
_id: '5f1295181ebf00dd0070de1',
title: 'dummy',
Description: 'asfd',
Price: 50,
createdAt: '2020-07-18T06:22:09.037Z',
updatedAt: '2020-07-18T06:22:09.037Z',
__v: 0,
id: '5f12951081ebf00dd0070de1',
},
],
})
export const mutations = {
saveAssignments(state, newAssignments) {
state.assignments = state.assignments.concat(newAssignments)
},
}
export const actions = {
async fetchAssignment({ commit }) {
const data = await this.$axios.$get('assignments')
commit('saveAssignments', data)
},
}
Any help will be appreciated
Found the solution
I just had to add the return statement before the dispatch function in fetch()
fetch(){
return this.$store.dispatch('assignment/fetchAssignment')
}
Found my answer here
Nuxtjs async await in a page doesnt work on page refresh
The reason why I am writing here because I just got a job as a front-end developer and on the first day they threw at me a big project and I lost, very lost, hopeless.
My job would be that I am having a home page where there is a table with some information for example date, hours, the daily wind speed, daily celsius, and under the table there would be information which can be generated from a config panel.
So basically with Vue-router am having two pages, one with the home and one with the config panel, now in the config panel I am having a form where you can write your text you want to display to the home page and my problem is that I have no clue how to display that text from one router to another I tried to make a method where on submitting the form it should somehow commit that message to my Vuex state but when I am about to write it out to the home page it is now showing,
This is what I have in my modules (vuex file) :
const state = {
message: '',
};
const getters = {
message: (state) => {
return state.message;
},
};
const actions = {
setMessage: ({
commit,
state
}, newValue) => {
commit('SET_MESSAGE', newValue);
return state.message;
},
};
const mutations = {
SET_MESSAGE: (state, newValue) => {
state.message = newValue;
console.log(state.message);
},
};
export default {
state,
getters,
actions,
mutations,
};
when I am console logging the state.message the text which got submitted is there now I need to put this text to my homepage, please help me with that I know that this should be an easy one but I cannot solve it.
On home page you should add
created() {
this.$store.dispatch('SET_MESSAGE');
}
This code will call SET_MESSAGE
computed: {
...mapGetters({
message: 'message',
}),
}
After adding this part you can take message value simple call "this.message" in methods or "message" in template
i am using Vuex and Firebase Authentication. I got stuck when reload the page. firebase.auth().onAuthStateChanged take time to response. But i need at the same time when reload the page. I have seen many tutorials in internet, most of them is router guard, but that i don’t want. I have some route where the user has login, then can navigate to this route.
App.vue where i am applying.
created () {
firebase.auth().onAuthStateChanged(async user =>{
if (user){
await this.$store.dispatch('autoSignIn',user)
}
})
}
Here is my vuex action theat trigger when page reload to auto sign in if a user was logged before reload the page.
autoSignIn ({commit}, payload) {
commit('setUser',{email:payload.email, userId:payload.uid})
}
This is my getter
isAuthenticated:state => {
return state.user !== null && state.user !== undefined ? state.user : null
}
Here is where i am calling my getter isAuthenticated.
getEventsByUser({getters,commit}){
let data = [];
firebase.database().ref('usuario/' + getters.isAuthenticated.userId + '/eventos/')
.on("value", eventos =>{
eventos.forEach(evento =>{
data.push({"id":evento.key, ...evento.val()})
});
commit('setEventsByUser',data)
})
},
And this is the component which dispatch the action
<template>
<div>
<div v-for="(event,id) in getEventsByUser" :key="id">
{{event}}
</div>
</div>
</template>
<script>
export default {
name: "MyEvents",
computed:{
getEventsByUser(){
return this.$store.getters.getEventsByUser;
},
},
mounted() {
this.$store.dispatch('getEventsByUser')
},
}
Here is the error when i reload the page
When the page loads, Firebase checks whether the ID token that is stored for the user is still valid. This requires that it calls the server, so it may take a moment. During this check the user will be null, so your code needs to handle that everywhere.
In your onAuthStateChanged handler you handle this correctly with:
firebase.auth().onAuthStateChanged(async user =>{
if (user){
But then in getEventsByUser you assume there is a user, which (as shown by the error message) is not true. So you'll want to add a check there, to see if there's a user, before attaching the listener to the database:
getEventsByUser({getters,commit}){
let data = [];
if (getters.isAuthenticated) {
firebase.database().ref('usuario/' + getters.isAuthenticated.userId + '/eventos/')
...