Hello,
First of all, I'm not sure I'm doing it correctly, but here is my statement.
This is a « pretty simple » use case where I want to register an user and get the state updated with his data.
<template>
<div class="UserMenu">
<div class="ButtonWrapper">
<Button :color="primaryColor">{{ $t('header.becomeCoach') }}</Button>
</div>
<div class="ButtonWrapper" v-if="!user">
<Button :color="primaryColor" @click="displayLogin">{{ $t('header.connect') }}</Button>
<div style="display: flex; justifyContent: center">
<LoginModal @onRegister="register" :register-error="registerErrorMsg" />
</div>
</div>
<div v-else>
<Button class="Connected-Button" @click="showMenu = !showMenu">
<img src="https://placeimg.com/40/40/people" />
<span> {{ user.firstname }} </span>
<icon :name="showMenu ? 'chevron-up' : 'chevron-down'" />
</Button>
<div v-if="showMenu" class="Connected-Menu">
<div>Email: {{ user.email }}</div>
<a href="">Mon profil</a>
<a href="" @click="logout">Se deconnecter</a>
</div>
</div>
</div>
</template>
<script lang="ts">
import gql from "graphql-tag";
import Vue from "vue";
import LoginModal from "../../components/Home/LoginModal.vue";
import Button from "../Common/Button.vue";
import { colors } from "../../services/variables";
export default Vue.extend({
apollo: {
user: {
fetchPolicy: "cache-and-network",
query: gql`
{
user: me {
_id
email
firstname
}
}`,
},
},
components: { Button, LoginModal },
data() {
return {
primaryColor: colors.primary,
registerErrorMsg: null,
showMenu: false,
user: null,
};
},
methods: {
displayLogin() {
this.$modal.show("login-modal");
},
logout(e: Event) {
e.preventDefault();
const request = new XMLHttpRequest();
request.open("POST", "http://localhost:3001/logout");
request.withCredentials = true;
request.send();
// TODO: CALL client.resetStore()
this.user = null;
},
register(values) {
const request = new XMLHttpRequest();
request.open("POST", "http://localhost:3001/register");
request.setRequestHeader("Content-Type", "application/json");
request.withCredentials = true;
request.addEventListener("load", (event) => {
const { status, response } = request;
if (status === 401) {
this.registerErrorMsg = this.$t("home.accountModal.validation.emailAlreadyTaken");
return;
}
this.registerErrorMsg = null;
this.$modal.hide("login-modal");
this.$apollo.queries.user.refetch();
// TODO: this could be counter solution
// this.user = JSON.parse(response).user;
});
request.send(JSON.stringify(values));
},
},
});
</script>
As you can see I'm using this.$apollo.queries.user.refetch(); in order to refetch the user metadata after setting the jwt as a cookie while returning the response from the XHR.
The request is correctly outgoing and return the correct result from Network tab, but randomly, I don't get my user data updated. If I refresh the tab, it update and work properly.
I also tried to use $forceUpdate() nothing changed. Also setTimeout to avoid race condition…
Am I doing wrong ? Am I thinking in a bad way ?
Thanks for help,
Best regards
You can write the user data into the store with writeQuery: https://www.apollographql.com/docs/react/advanced/caching.html#writequery-and-writefragment
@Akryum I updated my whole code in order to use mutations now, Just in case that was buggy, what I have now is the following :
<template>
<div class="UserMenu">
<div class="ButtonWrapper">
<Button :color="primaryColor">{{ $t('header.becomeCoach') }}</Button>
</div>
<div class="ButtonWrapper" v-if="$apollo.queries.me.loading">
<Button :color="primaryColor">{{ $t('commons.loading') }}</Button>
</div>
<template v-else>
<div class="ButtonWrapper" v-if="!me">
<Button :color="primaryColor" @click="displayLogin">{{ $t('header.connect') }}</Button>
<div style="display: flex; justifyContent: center">
<LoginModal
@onLogin="login"
:login-error="loginErrorMsg" />
</div>
</div>
<div v-else>
<Button class="Connected-Button" @click="showMenu = !showMenu">
<img src="https://placeimg.com/40/40/people" />
<span> {{ me.firstname }} </span>
<icon :name="showMenu ? 'chevron-up' : 'chevron-down'" />
</Button>
<div v-if="showMenu" class="Connected-Menu">
<strong>{{ me.email }}</strong>
<a href="">Mon profil</a>
</div>
</div>
</template>
</div>
</template>
<script lang="ts">
import gql from "graphql-tag";
import Vue from "vue";
import LoginModal from "../../components/Home/LoginModal.vue";
import Button from "../Common/Button.vue";
import { DataProxy } from "apollo-cache";
import { colors } from "../../services/variables";
const meQuery = gql`
{
me {
_id
email
firstname
}
}
`;
export default Vue.extend({
apollo: {
me: {
query: meQuery,
},
},
components: { Button, LoginModal },
data() {
return {
loginErrorMsg: null,
me: false,
primaryColor: colors.primary,
registerErrorMsg: null,
showMenu: false,
};
},
methods: {
displayLogin() {
this.$modal.show("login-modal");
},
async login(values) {
try {
await this.$apollo.mutate({
mutation: gql`mutation login($email: String!, $password: String!) {
login(email: $email, password: $password) {
_id
email
firstname
}
}`,
update: (store: DataProxy, { data: { login: me } }) => {
store.writeQuery({
data: {
me,
},
query: meQuery,
});
},
variables: values,
});
this.loginErrorMsg = null;
this.$modal.hide("login-modal");
} catch (error) {
this.loginErrorMsg = this.$t("home.accountModal.validation.badCredentials");
}
},
},
});
</script>
My cache is getting correctly updated, I checked it using the dev tool, but my data isn't getting updated, like it was not reactive…
Any idea ?
Regards
@Akryum Sorry for UP, but still get stuck with that, If you take time to answer, it'll be a pleasure to udpate documentation through PR for the subject…
Seems, I'm not alone as shown with this "+1"
Regards
@Akryum Still more Thumb on my post…
I figured out something new. Instead of triggering an error on not Authenticated user, I return an empty user with empty fields (I was using https://github.com/kkemple/graphql-auth before with that me resolver).
Before :
me: withAuth((obj, values, context) => context.auth.user),
Now :
me: (obj, values, context) => context.auth.user || { _id: "", email: "", firstname: "" },
Now the request is correctly reactive. And my view is updated accordingly.
I think your lib have a Reactivity glitch when the graph response is an error. Any idea what can cause that ?
Thanks for the response. Hope this can help improve that soft.
Regards
Most helpful comment
@Akryum I updated my whole code in order to use mutations now, Just in case that was buggy, what I have now is the following :
My cache is getting correctly updated, I checked it using the dev tool, but my data isn't getting updated, like it was not reactive…
Any idea ?
Regards