Javascript 基于Electron vue的Electron app中Vuex突变的奇怪行为

Javascript 基于Electron vue的Electron app中Vuex突变的奇怪行为,javascript,vue.js,vuejs2,electron,vuex,Javascript,Vue.js,Vuejs2,Electron,Vuex,我正在尝试用Vue和Electron构建一个简单的任务管理应用程序。我的设置基于与Vuex商店的连接。 用户可以通过模式向列表中添加新项目(并编辑现有项目)。模态将信息发送到存储操作,然后该操作调用一个变异来更新存储并将一个新项推送到列表项数组 这是设置:LayerItem是LayerMap的子级。数据从父级LayerMap组件中的存储中接收,然后通过道具提供给子级 重新创建问题:通过层组件中的showEditItemDialog创建新项目。在SAVE\u LAYER\u项目中mutation将

我正在尝试用Vue和Electron构建一个简单的任务管理应用程序。我的设置基于与Vuex商店的连接。 用户可以通过模式向列表中添加新项目(并编辑现有项目)。模态将信息发送到存储操作,然后该操作调用一个变异来更新存储并将一个新项推送到列表项数组

这是设置:
LayerItem
LayerMap
的子级。数据从父级
LayerMap
组件中的存储中接收,然后通过道具提供给子级

重新创建问题:通过
组件中的
showEditItemDialog
创建新项目。在
SAVE\u LAYER\u项目中
mutation将创建一个新ID并分配给该新项目。之后,新项目将被推送到
层.items
数组。UI将被更新,并且创建的项目可见<代码>项目。文本显示正确。但是,
item.id
是不同的。我在变异中加入了一个
console.log
。记录的id与此处
{{item.id}

组件的UI中显示的id不匹配。因此,在创建新项目后尝试编辑/更新新项目时,变异将创建新项目,而不是更新现有项目,因为在存储阵列中找不到模式接收的ID

我知道有很多代码,我试着删除尽可能多的不必要的代码。在下面的示例中,我创建了一个新项目“test”,您可以看到存储的ID与UI中显示的ID不匹配

终端日志的屏幕截图

来自DevTools控制台的屏幕截图

Vue DevTools商店的屏幕截图

用户界面截图

LayerMap.vue

// 'layers' is a computed property and gets data from the store
        <draggable
          v-model="layers"
          v-bind="getDragOptions"
        >
          <Layer v-for="(layer, index) in layers" :key="index" :layer="layer"></Layer>
        </draggable>
        <DetailsModal></DetailsModal>

// Inside computed
  computed: {
    layers() {
      return this.$store.getters.allLayers
    }
  }

以前从未开发过Electron应用程序,所以我花了一些时间进行了深入研究,但我想我做到了!:)

每个electron应用程序至少有两个进程-主进程(负责打开浏览器窗口)和渲染器(Vue应用程序运行的地方)。如果在代码中使用
console.log
,则从主进程调用的输出显示-
console.log
仅显示在终端窗口中(用于在开发模式下启动应用程序),从渲染器进程调用的
console.log
仅显示在开发工具中

但是你的基因突变记录在这两种情况下都会出现!这意味着代码必须同时在两个进程中运行,对吗?但是怎么做呢

看起来,模板有一个选项(设置项目时必须打开)可以使用,特别是
createSharedMutations
插件。它可以用于在主进程和所有渲染器进程之间共享相同的Vuex存储(从技术上讲,每个进程都有自己的存储,但状态是同步的)。它的工作原理如下:

  • 您启动您的操作(在渲染器过程中)
  • 操作在渲染器进程中被取消(这就是为什么在开发工具中看不到任何来自操作的日志),并通知主进程执行该操作
  • 现在,如果该操作(在main中运行)提交了一个变异,那么变异代码将在主进程中执行(第一个屏幕截图中的Terminal-id日志为空),然后有效负载(现在是新生成的
    id
    a)被序列化为JSON(),并传递给每个渲染器进程以执行相同的变异(因此保持所有存储同步)。在这里,您的变异将第二次执行(第二次屏幕截图,其中包含来自DevTools的日志)项已分配了
    id
    (A),但它不在项列表中,因此您的代码将分配新的
    id
    (B)并将其推送到集合中
  • id
    B显示在屏幕上
  • 现在,如果您开始编辑并调用action来保存,第3点中描述的所有内容都将再次发生,但现在在主进程中执行的变异会看到带有
    id
    B的项,而该项不在其项集合中。因此,它会分配新的
    id
    (C覆盖B)所以,在渲染器进程中执行的变异会再次看到不在集合中的id为
    C的项……以此类推

  • 解决方案显然是在存储配置中禁用
    createSharedMutations
    插件(应该在
    /renderer/store/index.js
    )。如果您确实需要跨主进程/渲染器进程同步存储,您需要重写您的变体…

    太多代码:)…您正在谈论您的
    图层项目组件
    显示错误的
    id
    (顺便问一下,文本如何?),但是
    项目
    通过道具传递给组件。因此,使用组件(并传递项目)的代码会更有趣(可能您的组件显示的是完全不同的项目?@MichalLevý感谢您的回复。我试图更新我的问题,删除不必要的代码并包含父组件。你知道出了什么问题吗?还不知道<代码>{this.item.text}
    LayerItem.vue
    中是真实的?第一步。确认存储中
    id
    的值-它是原始(记录的)
    id
    还是
    id
    LayerItem.vue
    组件所示?再次使用Vue开发工具…@MichalLevý,感谢您的帮助!非常感谢!是,
    this.item.text
    显示了正确的值(我更新了原始问题中的文本)。使用Vue开发工具,商店显示的是来自
    LayerItem.Vue
    的值,而不是商店记录的值。哇,非常感谢您为此付出了这么多努力!读完这篇文章后,我做了一些研究并检查了vuex商店的设置。我同时删除了
    createPersistedState()
    createSharedMutations()
    插件,并将这一行添加到
    main.js
    window.localStorage.clear()
    。现在我
    // 'layer' gets passed from parent as prop
         <span primary-focus @click="showEditItemDialog">Add Item</span> 
         <draggable v-model="items" v-bind="dragOptions" class="items">
            <LayerItem v-for="item in items" :item="item" :layer="layer" :key="item.id"></LayerItem>
          </draggable>
    
    // 'items' is a computed property
        items: {
          get() {
            return this.layer.items
          }
        }
    
    // Function to handle 'Add Item' click and send event which will be handled by DetailsModal.vue
      methods: {
        showEditItemDialog() {
          let payload = {
            layer: this.layer,
            item: {
              id: '',
              text: ''
            }
          }
          this.$bus.$emit('item-editing', payload)
        }
      }
    
    // Layer Item Component
      <div class="layer-item" @click.prevent="startEditing">
        <div class="item-body">
          <p>{{ this.item.text }}</p>
          <p>{{ item.id }}</p>
        </div>
      </div>
    
    // Event will be sent on click with layer item details as parameter
      methods: {
        startEditing() {
          let payload = {
            layer: this.layer,
            item: {
              id: this.item.id,
              text: this.item.text
            }
          }
          this.$bus.$emit('item-editing', payload)
        }
      }
    }
    
    // 'editLayerForm' contains layer item id and text
          <p>{{editLayerForm.id}}</p>
          <div class="bx--form-item">
            <input
              type="text"
              v-model="editLayerForm.text"
            />
          </div>
    
    // Inside <script>, event is received and handled, 'editLayerForm' will be updated with payload information
      mounted() {
        this.$bus.$on('item-editing', this.handleModalOpen)
      },
      methods: {
        handleModalOpen(payload) {
          this.layer = payload.layer
          this.editLayerForm.id = payload.item.id
          this.editLayerForm.text = payload.item.text
          this.visible = true
          console.log('editing', payload)
        },
        handleModalSave() {
          let payload = {
            layerId: this.layer.id,
            item: {
              id: this.editLayerForm.id,
              text: this.editLayerForm.text
            }
          }
          console.log('save', payload)
          this.$store.dispatch('saveLayerItem', payload)
        }
      }
    
    const actions = {
      saveLayerItem: ({ commit }, payload) => {
        console.log('action item id', payload.item.id)
        commit('SAVE_LAYER_ITEM', payload)
      }
    }
    
    const mutations = {
      SAVE_LAYER_ITEM: (state, payload) => {
        let layer = state.map.layers.find(l => l.id === payload.layerId)
        let itemIdx = layer.items.findIndex(item => item.id === payload.item.id)
        console.log('mutation item id', payload.item.id)
    
        if (itemIdx > -1) {
          // For existing item
          console.log('update item', payload.item)
          Vue.set(layer.items, itemIdx, payload.item)
        } else {
          // For new item
          payload.item.id = guid()
          console.log('save new item', payload.item)
          layer.items.push(payload.item)
        }
      }
    }