Vuex-在新窗口/选项卡中令人困惑的突变有效载荷

时间:2018-11-22 07:20:15

标签: vue.js vuex

我有一个由Express提供的简单VueJS SPA。 Express还处理Vue前端调用的API端点。 Express已连接到Postgres,并且API端点与数据库交互(执行基本的CRUD操作)。

在我的数据库中,我只有一个“病人”表,其中包含“ first_name”,“ last_name”,“ date_of_birth”和“ id”列。

在PatientList.vue组件的created()挂钩中,查询所有患者的数据库,并将此信息保存到组件数据中,并使用v-for循环显示。

我的PatientList.vue代码是:

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

为了编辑患者,我具有路由器链接到编辑页面。路由器链接具有点击处理程序,可以从v-for循环(即单个患者对象)中迭代传入的参数。我有4个与此相关的突变

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;
  },

此外,我的PatientEdit.vue代码是:

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

我的理由是避免对数据库的不必要请求。

一切正常。我有一个store.subscription设置为将Vuex状态保存到localStorage(刷新此应用程序时用于会话持久性)。 存储订阅日志的状态和变化,一切正常,像这样:

First store output

如果我打开一个新的标签页或窗口(保持不变的cookie),并尝试执行相同的更新操作,那么我的商店订阅就会失败,并且无法使用来自Vuex的患者信息自动填充我的PatientEdit页面。

根据输出,突然的突变正在提交我从未指定过的东西,像这样:

Store output 2

为什么会这样?

感谢阅读。

注意:如果我错过了解决此问题所需的信息,请告诉我。

编辑1:

Vuex商店:

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;

1 个答案:

答案 0 :(得分:0)

您最终会遇到“无法对循环JSON进行字符串化”错误,因为您将状态以及吸气剂,变异和动作都转换为字符串。这些包含对您要进行字符串化的对象的引用,这将导致无限循环。

这在您的第一次运行中不是问题,因为那时localStorage仍然为空。您可以正确地对状态进行分类,但是当您重新加载时,将运行以下行:

this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));

此行用商店替换您的状态,并用localStorage中的内容进行扩展。如果将store替换为state,则效果会更好。