Vuex problems, important project, MapActions,MapGetters - javascript

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

Related

Wait for data in mapstate to finish loading

I have stored a userProfile in Vuex to be able to access it in my whole project. But if I want to use it in the created() hook, the profile is not loaded yet. The object exists, but has no data stored in it. At least at the initial load of the page. If I access it later (eg by clicking on a button) everything works perfectly.
Is there a way to wait for the data to be finished loading?
Here is how userProfile is set in Vuex:
mutations: {
setUserProfile(state, val){
state.userProfile = val
}
},
actions: {
async fetchUserProfile({ commit }, user) {
// fetch user profile
const userProfile = await fb.teachersCollection.doc(user.uid).get()
// set user profile in state
commit('setUserProfile', userProfile.data())
},
}
Here is the code where I want to acess it:
<template>
<div>
<h1>Test</h1>
{{userProfile.firstname}}
{{institute}}
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
data() {
return {
institute: "",
}
},
computed: {
...mapState(['userProfile']),
},
created(){
this.getInstitute();
},
methods: {
async getInstitute() {
console.log(this.userProfile); //is here still empty at initial page load
const institueDoc = await this.userProfile.institute.get();
if (institueDoc.exists) {
this.institute = institueDoc.name;
} else {
console.log('dosnt exists')
}
}
}
}
</script>
Through logging in the console, I found out that the problem is the order in which the code is run. First, the method getInstitute is run, then the action and then the mutation.
I have tried to add a loaded parameter and played arround with await to fix this issue, but nothing has worked.
Even if you make created or mounted async, they won't delay your component from rendering. They will only delay the execution of the code placed after await.
If you don't want to render a portion (or all) of your template until userProfile has an id (or any other property your users have), simply use v-if
<template v-if="userProfile.id">
<!-- your normal html here... -->
</template>
<template v-else>
loading user profile...
</template>
To execute code when userProfile changes, you could place a watcher on one of its inner properties. In your case, this should work:
export default {
data: () => ({
institute: ''
}),
computed: {
...mapState(['userProfile']),
},
watch: {
'userProfile.institute': {
async handler(institute) {
if (institute) {
const { name } = await institute.get();
if (name) {
this.institute = name;
}
}
},
immediate: true
}
}
}
Side note: Vue 3 comes with a built-in solution for this pattern, called Suspense. Unfortunately, it's only mentioned in a few places, it's not (yet) properly documented and there's a sign on it the API is likely to change.
But it's quite awesome, as the rendering condition can be completely decoupled from parent. It can be contained in the suspensible child. The only thing the child declares is: "I'm currently loading" or "I'm done loading". When all suspensibles are ready, the template default is rendered.
Also, if the children are dynamically generated and new ones are pushed, the parent suspense switches back to fallback (loading) template until the newly added children are loaded. This is done out of the box, all you need to do is declare mounted async in children.
In short, what you were expecting from Vue 2.

How to add my subscription data to update my previous query

I have one query and one subscription, what I am trying to do is add my data to previous query so that it shows the full list.
I have one query which is returning me list of students and I am rendering that on UI like below
function Test(props) {
const { loading, data: dta } = useQuery(GETSTUDENTS);
const { data: d } = useSubscription(GETSUBSTUDENTS, {
onSubscriptionData: ({ subscriptionData: { data } }) => {
let fname = data.getSubStudent.fname;
let lname = data.getSubStudent.lname;
dta.getStudents.push({ fname, lname });
},
});
return (
<div className="">
{dta &&
dta.getStudents.map((li) => {
<div>
<p>{li.fname}</p>
<p>{li.lname}</p>
</div>;
})}
</div>
);
}
export default Test;
But the main issue is the above one is not updating the cache so when I change the routes and come bqack again it takes the previous data only.
So What I wnat to know na what is the best way to do this, I have check subscribeToMore also but did not get idea How to implement that and how it works with hooks.
I am getting some data from subscription and on that basis I want to change some other part so can I use refetchQueries I did not found any good tutorial which uses hooks (react-apollo-hooks) using qraphql
First, you can just use the pooling option of the useQuery instead of subscription,
I suggest you check it.
From Apollo docs:
"In the majority of cases, your client should not use subscriptions to
stay up to date with your backend. Instead, you should poll
intermittently with queries, or re-execute queries on demand when a
user performs a relevant action."
Apollo subscription
If you still want to use the subscription I think you should use the subscribeToMore and to update your cache policy inside the apollo cache file:
const cache = new InMemoryCache({
typePolicies: {
Agenda: {
fields: {
tasks: {
merge(existing = [], incoming: any[]) {
return [...existing, ...incoming];
},
},
},
},
},
});
You can read more about it here: merge cahce
And check that video: youtube apollo cache

Showing modal on successfully posting data from redux

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 ??

(Nuxt) Page not re-rendering data on reload

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

firebase.auth().onAuthStateChanged getting null after refresh page in vuex

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/')
...

Categories

Resources