Vuex - 新窗口/选项卡中的令人困惑的变异有效负载

问题描述 投票:0回答:1

我有一个由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>

为了编辑病人,我有路由器链接来编辑页面。 Router-link具有click-handler,传入的参数可以从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;
vue.js vuex
1个回答
0
投票

你最终会得到一个“无法串通循环JSON”的错误,因为你正在转变状态,而且还将getters,mutation和actions转换成字符串。它们包含对您尝试进行字符串化的对象的引用,从而导致无限循环。

这在您的第一次运行中不是问题,因为您的localStorage仍为空。您正确地将您的状态字符串化,但是当您重新加载以下行时:

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

此行用您的商店替换您的州,并使用localStorage中的内容进行扩展。如果用store替换state,事情应该会好得多。

© www.soinside.com 2019 - 2024. All rights reserved.