Vuex - Baffling mutation payload in new window/tab
I have a simple VueJS SPA served by Express. Express also handles API endpoints called by Vue front-end.
Express is connected to Postgres, and API endpoints interact with the database (perform basic CRUD operations).
In my database, I have a single "patient" table, with columns "first_name", "last_name", "date_of_birth", and "id".
In the created() hook of PatientList.vue component, database is queried for all patients, and this information is saved to component data, displayed using v-for loop.
My PatientList.vue code is:
<script>
import auth from '@/auth/authenticator';
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientsList',
},
data() {
return {
patients: ,
}
},
computed: {
accessTokenGetter: {
get: function () {
return this.$store.getters.accessToken;
},
},
patientEditStatusGetter: {
get: function () {
return this.$store.getters.g_patientEditStatusCheck;
},
},
},
methods: {
...mapMutations([
'm_startPatientEditProcess',
'm_endPatientEditProcess',
'm_clearPatientEditState',
'm_cachePatient'
]),
cachePatientHandler(ptnt) {
console.log('PatientList.vue method cachePatientHandler', ptnt);
var patientObject = {
'date_of_birth': ptnt.date_of_birth.split('T')[0],
'first_name': ptnt.first_name,
'last_name': ptnt.last_name,
'patient': ptnt.patient,
'uid': ptnt.uid
}
this.m_endPatientEditProcess(false);
this.m_clearPatientEditState('');
this.m_startPatientEditProcess(true);
this.m_cachePatient(patientObject);
},
getPatients() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://voyager.wrk.health/patients/index');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.setRequestHeader('Cache-control', 'no-cache');
xhr.onload = () => {
var data = JSON.parse(xhr.response);
for( var i=0, r = data.results; i<r.length; i++ ){
this.patients.push(r[i]);
}
};
xhr.onerror = () => {
console.log(xhr.statusText);
};
xhr.send();
},
},
beforeCreate() {
},
created() {
console.log('PatientList.vue created()');
if(auth.isUserLogged()){
this.getPatients();
} else {
router.go('/');
}
},
};
</script>
In order to edit a patient, I have router-link to edit page. Router-link has click-handler, argument passed in is iterable from v-for loop (i.e. single patient object). I have 4 mutations related to this
const mutations = {
m_startPatientEditProcess(state, trueStatus) {
console.log('Vuex patient m_startPatientEditProcess');
state.patientEditStatus = trueStatus;
},
m_endPatientEditProcess(state, falseStatus) {
console.log('Vuex patient m_endPatientEditProcess');
state.patientEditStatus = falseStatus;
},
m_clearPatientEditState(state, emptyString) {
console.log('Vuex patient m_clearPatientEditState');
state.patientDetails.date_of_birth = emptyString;
state.patientDetails.first_name = emptyString;
state.patientDetails.last_name = emptyString;
state.patientDetails.patient = emptyString;
state.patientDetails.uid = emptyString;
},
m_cachePatient(state, patientObj) {
console.log('Vuex patient m_cachePatient, received: ', patientObj);
state.patientDetails.date_of_birth = patientObj.date_of_birth;
state.patientDetails.first_name = patientObj.first_name;
state.patientDetails.last_name = patientObj.last_name;
state.patientDetails.patient = patientObj.patient;
state.patientDetails.uid = patientObj.uid;
},
Also, my PatientEdit.vue code is:
<script>
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientEdit',
},
data() {
return {
patientToEdit: {
first_name: '',
last_name: '',
date_of_birth: '',
patient: '',
uid: '',
},
patientDetailsLoaded: false,
}
},
computed: {
patientToEditDetailsGetter: {
get: function() {
return this.$store.getters.g_patientToEditDetails;
}
},
accessTokenGetter: {
get: function() {
return this.$store.getters.accessToken;
}
}
},
methods: {
...mapMutations([
'm_endPatientEditProcess',
'm_clearPatientEditState',
]),
populatePatientEditState() {
const pDeets = this.patientToEditDetailsGetter;
this.patientToEdit.first_name = pDeets.first_name;
this.patientToEdit.last_name = pDeets.last_name;
this.patientToEdit.date_of_birth = pDeets.date_of_birth;
this.patientToEdit.patient = pDeets.patient;
this.patientToEdit.uid = pDeets.uid;
this.patientDetailsLoaded = true;
},
submitUpdatedPatientDetails() {
const payload = Object.assign({}, this.patientToEdit);
const xhr = new XMLHttpRequest();
xhr.open('PUT', `https://voyager.wrk.health/patients/update/${payload.uid}`)
xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.onload = async () => {
try {
await console.log(xhr.response);
await console.log('Sent patient data to update endpoint n Ready to be redirected.');
await Promise.all([this.m_endPatientEditProcess(false), this.m_clearPatientEditState('')]);
await this.$router.push('/patients/index');
} catch (e) {
throw new Error(e);
}
}
xhr.send(JSON.stringify(payload));
}
},
created() {
this.populatePatientEditState();
},
};
</script>
My reasoning was to avoid unnecessary request to database.
Everything works as intended. I have a store.subscription set up to save Vuex state to localStorage (for session persistence when this application is refreshed).
Store subscription logs state and mutation, everything is normal like so:
First store output
If I open a new tab or window (cookies left untouched), and try to perform the same update operations, my store subscription freaks out, and I cannot auto-populate my PatientEdit page with patient information from Vuex.
According to the output, suddenly mutation is committing things that I never specified like so:
Store output 2
Why does this happen?
Thanks for reading.
NB: If I have missed information necessary to figure this behaviour out, please let me know.
Edit 1:
Vuex store:
import Vue from 'vue';
import Vuex from 'vuex';
import session from './modules/session';
import patient from './modules/patient';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
session,
patient,
},
mutations: {
initStore(state) {
console.log('Vuex root state checking for local snapshot');
if (localStorage.getItem('store')) {
console.log('Snapshot found, hydrating...');
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
}
},
},
});
store.commit('initStore');
store.subscribe((mutation, state) => {
console.warn('Subscription detected');
console.log('mutation: ', mutation);
console.log('state: ', state);
localStorage.setItem('store', JSON.stringify(state));
});
export default store;
vue.js vuex
add a comment |
I have a simple VueJS SPA served by Express. Express also handles API endpoints called by Vue front-end.
Express is connected to Postgres, and API endpoints interact with the database (perform basic CRUD operations).
In my database, I have a single "patient" table, with columns "first_name", "last_name", "date_of_birth", and "id".
In the created() hook of PatientList.vue component, database is queried for all patients, and this information is saved to component data, displayed using v-for loop.
My PatientList.vue code is:
<script>
import auth from '@/auth/authenticator';
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientsList',
},
data() {
return {
patients: ,
}
},
computed: {
accessTokenGetter: {
get: function () {
return this.$store.getters.accessToken;
},
},
patientEditStatusGetter: {
get: function () {
return this.$store.getters.g_patientEditStatusCheck;
},
},
},
methods: {
...mapMutations([
'm_startPatientEditProcess',
'm_endPatientEditProcess',
'm_clearPatientEditState',
'm_cachePatient'
]),
cachePatientHandler(ptnt) {
console.log('PatientList.vue method cachePatientHandler', ptnt);
var patientObject = {
'date_of_birth': ptnt.date_of_birth.split('T')[0],
'first_name': ptnt.first_name,
'last_name': ptnt.last_name,
'patient': ptnt.patient,
'uid': ptnt.uid
}
this.m_endPatientEditProcess(false);
this.m_clearPatientEditState('');
this.m_startPatientEditProcess(true);
this.m_cachePatient(patientObject);
},
getPatients() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://voyager.wrk.health/patients/index');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.setRequestHeader('Cache-control', 'no-cache');
xhr.onload = () => {
var data = JSON.parse(xhr.response);
for( var i=0, r = data.results; i<r.length; i++ ){
this.patients.push(r[i]);
}
};
xhr.onerror = () => {
console.log(xhr.statusText);
};
xhr.send();
},
},
beforeCreate() {
},
created() {
console.log('PatientList.vue created()');
if(auth.isUserLogged()){
this.getPatients();
} else {
router.go('/');
}
},
};
</script>
In order to edit a patient, I have router-link to edit page. Router-link has click-handler, argument passed in is iterable from v-for loop (i.e. single patient object). I have 4 mutations related to this
const mutations = {
m_startPatientEditProcess(state, trueStatus) {
console.log('Vuex patient m_startPatientEditProcess');
state.patientEditStatus = trueStatus;
},
m_endPatientEditProcess(state, falseStatus) {
console.log('Vuex patient m_endPatientEditProcess');
state.patientEditStatus = falseStatus;
},
m_clearPatientEditState(state, emptyString) {
console.log('Vuex patient m_clearPatientEditState');
state.patientDetails.date_of_birth = emptyString;
state.patientDetails.first_name = emptyString;
state.patientDetails.last_name = emptyString;
state.patientDetails.patient = emptyString;
state.patientDetails.uid = emptyString;
},
m_cachePatient(state, patientObj) {
console.log('Vuex patient m_cachePatient, received: ', patientObj);
state.patientDetails.date_of_birth = patientObj.date_of_birth;
state.patientDetails.first_name = patientObj.first_name;
state.patientDetails.last_name = patientObj.last_name;
state.patientDetails.patient = patientObj.patient;
state.patientDetails.uid = patientObj.uid;
},
Also, my PatientEdit.vue code is:
<script>
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientEdit',
},
data() {
return {
patientToEdit: {
first_name: '',
last_name: '',
date_of_birth: '',
patient: '',
uid: '',
},
patientDetailsLoaded: false,
}
},
computed: {
patientToEditDetailsGetter: {
get: function() {
return this.$store.getters.g_patientToEditDetails;
}
},
accessTokenGetter: {
get: function() {
return this.$store.getters.accessToken;
}
}
},
methods: {
...mapMutations([
'm_endPatientEditProcess',
'm_clearPatientEditState',
]),
populatePatientEditState() {
const pDeets = this.patientToEditDetailsGetter;
this.patientToEdit.first_name = pDeets.first_name;
this.patientToEdit.last_name = pDeets.last_name;
this.patientToEdit.date_of_birth = pDeets.date_of_birth;
this.patientToEdit.patient = pDeets.patient;
this.patientToEdit.uid = pDeets.uid;
this.patientDetailsLoaded = true;
},
submitUpdatedPatientDetails() {
const payload = Object.assign({}, this.patientToEdit);
const xhr = new XMLHttpRequest();
xhr.open('PUT', `https://voyager.wrk.health/patients/update/${payload.uid}`)
xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.onload = async () => {
try {
await console.log(xhr.response);
await console.log('Sent patient data to update endpoint n Ready to be redirected.');
await Promise.all([this.m_endPatientEditProcess(false), this.m_clearPatientEditState('')]);
await this.$router.push('/patients/index');
} catch (e) {
throw new Error(e);
}
}
xhr.send(JSON.stringify(payload));
}
},
created() {
this.populatePatientEditState();
},
};
</script>
My reasoning was to avoid unnecessary request to database.
Everything works as intended. I have a store.subscription set up to save Vuex state to localStorage (for session persistence when this application is refreshed).
Store subscription logs state and mutation, everything is normal like so:
First store output
If I open a new tab or window (cookies left untouched), and try to perform the same update operations, my store subscription freaks out, and I cannot auto-populate my PatientEdit page with patient information from Vuex.
According to the output, suddenly mutation is committing things that I never specified like so:
Store output 2
Why does this happen?
Thanks for reading.
NB: If I have missed information necessary to figure this behaviour out, please let me know.
Edit 1:
Vuex store:
import Vue from 'vue';
import Vuex from 'vuex';
import session from './modules/session';
import patient from './modules/patient';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
session,
patient,
},
mutations: {
initStore(state) {
console.log('Vuex root state checking for local snapshot');
if (localStorage.getItem('store')) {
console.log('Snapshot found, hydrating...');
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
}
},
},
});
store.commit('initStore');
store.subscribe((mutation, state) => {
console.warn('Subscription detected');
console.log('mutation: ', mutation);
console.log('state: ', state);
localStorage.setItem('store', JSON.stringify(state));
});
export default store;
vue.js vuex
I would first of all suggest to use the Vue devtools instead. chrome.google.com/webstore/detail/vuejs-devtools/…
– Sumurai8
Nov 22 '18 at 8:17
Am I correct in assuming that you are turning the entire Vuex store into JSON, including getters, mutations and actions?
– Sumurai8
Nov 22 '18 at 8:26
@Sumurai8 That is correct. I initially set that up for session persistence, storing the JWTs. I will update the post with the relevant store code.
– Scott
Nov 22 '18 at 8:53
add a comment |
I have a simple VueJS SPA served by Express. Express also handles API endpoints called by Vue front-end.
Express is connected to Postgres, and API endpoints interact with the database (perform basic CRUD operations).
In my database, I have a single "patient" table, with columns "first_name", "last_name", "date_of_birth", and "id".
In the created() hook of PatientList.vue component, database is queried for all patients, and this information is saved to component data, displayed using v-for loop.
My PatientList.vue code is:
<script>
import auth from '@/auth/authenticator';
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientsList',
},
data() {
return {
patients: ,
}
},
computed: {
accessTokenGetter: {
get: function () {
return this.$store.getters.accessToken;
},
},
patientEditStatusGetter: {
get: function () {
return this.$store.getters.g_patientEditStatusCheck;
},
},
},
methods: {
...mapMutations([
'm_startPatientEditProcess',
'm_endPatientEditProcess',
'm_clearPatientEditState',
'm_cachePatient'
]),
cachePatientHandler(ptnt) {
console.log('PatientList.vue method cachePatientHandler', ptnt);
var patientObject = {
'date_of_birth': ptnt.date_of_birth.split('T')[0],
'first_name': ptnt.first_name,
'last_name': ptnt.last_name,
'patient': ptnt.patient,
'uid': ptnt.uid
}
this.m_endPatientEditProcess(false);
this.m_clearPatientEditState('');
this.m_startPatientEditProcess(true);
this.m_cachePatient(patientObject);
},
getPatients() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://voyager.wrk.health/patients/index');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.setRequestHeader('Cache-control', 'no-cache');
xhr.onload = () => {
var data = JSON.parse(xhr.response);
for( var i=0, r = data.results; i<r.length; i++ ){
this.patients.push(r[i]);
}
};
xhr.onerror = () => {
console.log(xhr.statusText);
};
xhr.send();
},
},
beforeCreate() {
},
created() {
console.log('PatientList.vue created()');
if(auth.isUserLogged()){
this.getPatients();
} else {
router.go('/');
}
},
};
</script>
In order to edit a patient, I have router-link to edit page. Router-link has click-handler, argument passed in is iterable from v-for loop (i.e. single patient object). I have 4 mutations related to this
const mutations = {
m_startPatientEditProcess(state, trueStatus) {
console.log('Vuex patient m_startPatientEditProcess');
state.patientEditStatus = trueStatus;
},
m_endPatientEditProcess(state, falseStatus) {
console.log('Vuex patient m_endPatientEditProcess');
state.patientEditStatus = falseStatus;
},
m_clearPatientEditState(state, emptyString) {
console.log('Vuex patient m_clearPatientEditState');
state.patientDetails.date_of_birth = emptyString;
state.patientDetails.first_name = emptyString;
state.patientDetails.last_name = emptyString;
state.patientDetails.patient = emptyString;
state.patientDetails.uid = emptyString;
},
m_cachePatient(state, patientObj) {
console.log('Vuex patient m_cachePatient, received: ', patientObj);
state.patientDetails.date_of_birth = patientObj.date_of_birth;
state.patientDetails.first_name = patientObj.first_name;
state.patientDetails.last_name = patientObj.last_name;
state.patientDetails.patient = patientObj.patient;
state.patientDetails.uid = patientObj.uid;
},
Also, my PatientEdit.vue code is:
<script>
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientEdit',
},
data() {
return {
patientToEdit: {
first_name: '',
last_name: '',
date_of_birth: '',
patient: '',
uid: '',
},
patientDetailsLoaded: false,
}
},
computed: {
patientToEditDetailsGetter: {
get: function() {
return this.$store.getters.g_patientToEditDetails;
}
},
accessTokenGetter: {
get: function() {
return this.$store.getters.accessToken;
}
}
},
methods: {
...mapMutations([
'm_endPatientEditProcess',
'm_clearPatientEditState',
]),
populatePatientEditState() {
const pDeets = this.patientToEditDetailsGetter;
this.patientToEdit.first_name = pDeets.first_name;
this.patientToEdit.last_name = pDeets.last_name;
this.patientToEdit.date_of_birth = pDeets.date_of_birth;
this.patientToEdit.patient = pDeets.patient;
this.patientToEdit.uid = pDeets.uid;
this.patientDetailsLoaded = true;
},
submitUpdatedPatientDetails() {
const payload = Object.assign({}, this.patientToEdit);
const xhr = new XMLHttpRequest();
xhr.open('PUT', `https://voyager.wrk.health/patients/update/${payload.uid}`)
xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.onload = async () => {
try {
await console.log(xhr.response);
await console.log('Sent patient data to update endpoint n Ready to be redirected.');
await Promise.all([this.m_endPatientEditProcess(false), this.m_clearPatientEditState('')]);
await this.$router.push('/patients/index');
} catch (e) {
throw new Error(e);
}
}
xhr.send(JSON.stringify(payload));
}
},
created() {
this.populatePatientEditState();
},
};
</script>
My reasoning was to avoid unnecessary request to database.
Everything works as intended. I have a store.subscription set up to save Vuex state to localStorage (for session persistence when this application is refreshed).
Store subscription logs state and mutation, everything is normal like so:
First store output
If I open a new tab or window (cookies left untouched), and try to perform the same update operations, my store subscription freaks out, and I cannot auto-populate my PatientEdit page with patient information from Vuex.
According to the output, suddenly mutation is committing things that I never specified like so:
Store output 2
Why does this happen?
Thanks for reading.
NB: If I have missed information necessary to figure this behaviour out, please let me know.
Edit 1:
Vuex store:
import Vue from 'vue';
import Vuex from 'vuex';
import session from './modules/session';
import patient from './modules/patient';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
session,
patient,
},
mutations: {
initStore(state) {
console.log('Vuex root state checking for local snapshot');
if (localStorage.getItem('store')) {
console.log('Snapshot found, hydrating...');
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
}
},
},
});
store.commit('initStore');
store.subscribe((mutation, state) => {
console.warn('Subscription detected');
console.log('mutation: ', mutation);
console.log('state: ', state);
localStorage.setItem('store', JSON.stringify(state));
});
export default store;
vue.js vuex
I have a simple VueJS SPA served by Express. Express also handles API endpoints called by Vue front-end.
Express is connected to Postgres, and API endpoints interact with the database (perform basic CRUD operations).
In my database, I have a single "patient" table, with columns "first_name", "last_name", "date_of_birth", and "id".
In the created() hook of PatientList.vue component, database is queried for all patients, and this information is saved to component data, displayed using v-for loop.
My PatientList.vue code is:
<script>
import auth from '@/auth/authenticator';
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientsList',
},
data() {
return {
patients: ,
}
},
computed: {
accessTokenGetter: {
get: function () {
return this.$store.getters.accessToken;
},
},
patientEditStatusGetter: {
get: function () {
return this.$store.getters.g_patientEditStatusCheck;
},
},
},
methods: {
...mapMutations([
'm_startPatientEditProcess',
'm_endPatientEditProcess',
'm_clearPatientEditState',
'm_cachePatient'
]),
cachePatientHandler(ptnt) {
console.log('PatientList.vue method cachePatientHandler', ptnt);
var patientObject = {
'date_of_birth': ptnt.date_of_birth.split('T')[0],
'first_name': ptnt.first_name,
'last_name': ptnt.last_name,
'patient': ptnt.patient,
'uid': ptnt.uid
}
this.m_endPatientEditProcess(false);
this.m_clearPatientEditState('');
this.m_startPatientEditProcess(true);
this.m_cachePatient(patientObject);
},
getPatients() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://voyager.wrk.health/patients/index');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.setRequestHeader('Cache-control', 'no-cache');
xhr.onload = () => {
var data = JSON.parse(xhr.response);
for( var i=0, r = data.results; i<r.length; i++ ){
this.patients.push(r[i]);
}
};
xhr.onerror = () => {
console.log(xhr.statusText);
};
xhr.send();
},
},
beforeCreate() {
},
created() {
console.log('PatientList.vue created()');
if(auth.isUserLogged()){
this.getPatients();
} else {
router.go('/');
}
},
};
</script>
In order to edit a patient, I have router-link to edit page. Router-link has click-handler, argument passed in is iterable from v-for loop (i.e. single patient object). I have 4 mutations related to this
const mutations = {
m_startPatientEditProcess(state, trueStatus) {
console.log('Vuex patient m_startPatientEditProcess');
state.patientEditStatus = trueStatus;
},
m_endPatientEditProcess(state, falseStatus) {
console.log('Vuex patient m_endPatientEditProcess');
state.patientEditStatus = falseStatus;
},
m_clearPatientEditState(state, emptyString) {
console.log('Vuex patient m_clearPatientEditState');
state.patientDetails.date_of_birth = emptyString;
state.patientDetails.first_name = emptyString;
state.patientDetails.last_name = emptyString;
state.patientDetails.patient = emptyString;
state.patientDetails.uid = emptyString;
},
m_cachePatient(state, patientObj) {
console.log('Vuex patient m_cachePatient, received: ', patientObj);
state.patientDetails.date_of_birth = patientObj.date_of_birth;
state.patientDetails.first_name = patientObj.first_name;
state.patientDetails.last_name = patientObj.last_name;
state.patientDetails.patient = patientObj.patient;
state.patientDetails.uid = patientObj.uid;
},
Also, my PatientEdit.vue code is:
<script>
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientEdit',
},
data() {
return {
patientToEdit: {
first_name: '',
last_name: '',
date_of_birth: '',
patient: '',
uid: '',
},
patientDetailsLoaded: false,
}
},
computed: {
patientToEditDetailsGetter: {
get: function() {
return this.$store.getters.g_patientToEditDetails;
}
},
accessTokenGetter: {
get: function() {
return this.$store.getters.accessToken;
}
}
},
methods: {
...mapMutations([
'm_endPatientEditProcess',
'm_clearPatientEditState',
]),
populatePatientEditState() {
const pDeets = this.patientToEditDetailsGetter;
this.patientToEdit.first_name = pDeets.first_name;
this.patientToEdit.last_name = pDeets.last_name;
this.patientToEdit.date_of_birth = pDeets.date_of_birth;
this.patientToEdit.patient = pDeets.patient;
this.patientToEdit.uid = pDeets.uid;
this.patientDetailsLoaded = true;
},
submitUpdatedPatientDetails() {
const payload = Object.assign({}, this.patientToEdit);
const xhr = new XMLHttpRequest();
xhr.open('PUT', `https://voyager.wrk.health/patients/update/${payload.uid}`)
xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.onload = async () => {
try {
await console.log(xhr.response);
await console.log('Sent patient data to update endpoint n Ready to be redirected.');
await Promise.all([this.m_endPatientEditProcess(false), this.m_clearPatientEditState('')]);
await this.$router.push('/patients/index');
} catch (e) {
throw new Error(e);
}
}
xhr.send(JSON.stringify(payload));
}
},
created() {
this.populatePatientEditState();
},
};
</script>
My reasoning was to avoid unnecessary request to database.
Everything works as intended. I have a store.subscription set up to save Vuex state to localStorage (for session persistence when this application is refreshed).
Store subscription logs state and mutation, everything is normal like so:
First store output
If I open a new tab or window (cookies left untouched), and try to perform the same update operations, my store subscription freaks out, and I cannot auto-populate my PatientEdit page with patient information from Vuex.
According to the output, suddenly mutation is committing things that I never specified like so:
Store output 2
Why does this happen?
Thanks for reading.
NB: If I have missed information necessary to figure this behaviour out, please let me know.
Edit 1:
Vuex store:
import Vue from 'vue';
import Vuex from 'vuex';
import session from './modules/session';
import patient from './modules/patient';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
session,
patient,
},
mutations: {
initStore(state) {
console.log('Vuex root state checking for local snapshot');
if (localStorage.getItem('store')) {
console.log('Snapshot found, hydrating...');
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
}
},
},
});
store.commit('initStore');
store.subscribe((mutation, state) => {
console.warn('Subscription detected');
console.log('mutation: ', mutation);
console.log('state: ', state);
localStorage.setItem('store', JSON.stringify(state));
});
export default store;
vue.js vuex
vue.js vuex
edited Nov 22 '18 at 8:54
Scott
asked Nov 22 '18 at 7:20
ScottScott
175
175
I would first of all suggest to use the Vue devtools instead. chrome.google.com/webstore/detail/vuejs-devtools/…
– Sumurai8
Nov 22 '18 at 8:17
Am I correct in assuming that you are turning the entire Vuex store into JSON, including getters, mutations and actions?
– Sumurai8
Nov 22 '18 at 8:26
@Sumurai8 That is correct. I initially set that up for session persistence, storing the JWTs. I will update the post with the relevant store code.
– Scott
Nov 22 '18 at 8:53
add a comment |
I would first of all suggest to use the Vue devtools instead. chrome.google.com/webstore/detail/vuejs-devtools/…
– Sumurai8
Nov 22 '18 at 8:17
Am I correct in assuming that you are turning the entire Vuex store into JSON, including getters, mutations and actions?
– Sumurai8
Nov 22 '18 at 8:26
@Sumurai8 That is correct. I initially set that up for session persistence, storing the JWTs. I will update the post with the relevant store code.
– Scott
Nov 22 '18 at 8:53
I would first of all suggest to use the Vue devtools instead. chrome.google.com/webstore/detail/vuejs-devtools/…
– Sumurai8
Nov 22 '18 at 8:17
I would first of all suggest to use the Vue devtools instead. chrome.google.com/webstore/detail/vuejs-devtools/…
– Sumurai8
Nov 22 '18 at 8:17
Am I correct in assuming that you are turning the entire Vuex store into JSON, including getters, mutations and actions?
– Sumurai8
Nov 22 '18 at 8:26
Am I correct in assuming that you are turning the entire Vuex store into JSON, including getters, mutations and actions?
– Sumurai8
Nov 22 '18 at 8:26
@Sumurai8 That is correct. I initially set that up for session persistence, storing the JWTs. I will update the post with the relevant store code.
– Scott
Nov 22 '18 at 8:53
@Sumurai8 That is correct. I initially set that up for session persistence, storing the JWTs. I will update the post with the relevant store code.
– Scott
Nov 22 '18 at 8:53
add a comment |
1 Answer
1
active
oldest
votes
You end up with a "cannot stringify circular JSON" error, because you are turning the state, but also the getters, mutations and actions into a string. These contain references to the object you are trying to stringify, which results in an infinite loop.
This is not a problem in your first run, because your localStorage is still empty then. You correctly stringify your state, but when you reload the following line runs:
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
This line replaces your state with your store, extended with what you have in localStorage. If you replace store
with state
things should work much better.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53425723%2fvuex-baffling-mutation-payload-in-new-window-tab%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You end up with a "cannot stringify circular JSON" error, because you are turning the state, but also the getters, mutations and actions into a string. These contain references to the object you are trying to stringify, which results in an infinite loop.
This is not a problem in your first run, because your localStorage is still empty then. You correctly stringify your state, but when you reload the following line runs:
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
This line replaces your state with your store, extended with what you have in localStorage. If you replace store
with state
things should work much better.
add a comment |
You end up with a "cannot stringify circular JSON" error, because you are turning the state, but also the getters, mutations and actions into a string. These contain references to the object you are trying to stringify, which results in an infinite loop.
This is not a problem in your first run, because your localStorage is still empty then. You correctly stringify your state, but when you reload the following line runs:
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
This line replaces your state with your store, extended with what you have in localStorage. If you replace store
with state
things should work much better.
add a comment |
You end up with a "cannot stringify circular JSON" error, because you are turning the state, but also the getters, mutations and actions into a string. These contain references to the object you are trying to stringify, which results in an infinite loop.
This is not a problem in your first run, because your localStorage is still empty then. You correctly stringify your state, but when you reload the following line runs:
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
This line replaces your state with your store, extended with what you have in localStorage. If you replace store
with state
things should work much better.
You end up with a "cannot stringify circular JSON" error, because you are turning the state, but also the getters, mutations and actions into a string. These contain references to the object you are trying to stringify, which results in an infinite loop.
This is not a problem in your first run, because your localStorage is still empty then. You correctly stringify your state, but when you reload the following line runs:
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
This line replaces your state with your store, extended with what you have in localStorage. If you replace store
with state
things should work much better.
answered Nov 22 '18 at 9:37
Sumurai8Sumurai8
13.5k83263
13.5k83263
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53425723%2fvuex-baffling-mutation-payload-in-new-window-tab%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I would first of all suggest to use the Vue devtools instead. chrome.google.com/webstore/detail/vuejs-devtools/…
– Sumurai8
Nov 22 '18 at 8:17
Am I correct in assuming that you are turning the entire Vuex store into JSON, including getters, mutations and actions?
– Sumurai8
Nov 22 '18 at 8:26
@Sumurai8 That is correct. I initially set that up for session persistence, storing the JWTs. I will update the post with the relevant store code.
– Scott
Nov 22 '18 at 8:53