programing

Electron-Vue에 기반한 Electron 앱의 Vuex 돌연변이의 이상한 동작

bestcode 2022. 7. 16. 15:11
반응형

Electron-Vue에 기반한 Electron 앱의 Vuex 돌연변이의 이상한 동작

저는 Vue와 Electron으로 간단한 작업 관리 앱을 만들려고 합니다.제 설정은 Vuex 스토어의 전자-뷰 보일러 플레이트를 기반으로 합니다.사용자는 모달(modal)을 통해 목록에 새 항목을 추가하거나 기존 항목을 편집할 수 있습니다.모달은 정보를 스토어 액션으로 전송합니다.스토어는 변환을 호출하여 스토어를 갱신하고 새로운 아이템을 리스트 항목 배열에 푸시합니다.

설정입니다.LayerItemLayer의의의 입니다.LayerMap·····························································.LayerMap소품을 통해 아이들에게 공급합니다.

항목 만들기:항목을 만듭니다.showEditItemDialogLayer★★★★★★SAVE_LAYER_ITEM변환하면 새 ID가 생성되어 해당 새 항목에 할당됩니다.후, 은 그, 로, 로, 로, 로, 로, 에 푸시 됩니다.layer.items어레이 UI가 업데이트되고 생성된 항목이 표시됩니다. item.text을 사용하다item.id르르르르르는 함 a a a a를 포함했다.console.log변이 안에서요.가 "" "UI" "ID" "" 의 UI에와 일치하지 않습니다.LayerItem서의 컴포넌트<p>{{ item.id }}</p>그 결과, 신규 아이템을 작성한 후 편집/갱신을 시도하면 기존 아이템을 갱신하는 대신 모달에서 수신한ID를 스토어 어레이에서 찾을 수 없기 때문에 새로운 아이템이 생성됩니다.

많은 코드인 것을 알고 있기 때문에 불필요한 코드를 가능한 한 많이 제거하려고 했습니다.아래 예에서 새로운 항목 "test"를 작성했는데 저장된 ID가 UI에 표시된 ID와 일치하지 않습니다.

터미널 로그 스크린샷

DevTools 콘솔의 스크린샷

Vue DevTools 스토어의 스크린샷

UI로부터의 스크린샷

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

Layer.vue

// '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)
    }
  }
}

Details Modal(상세 모델)표시하다

// '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)
    }
  }

Store.js

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

Electron 앱을 만들어 본 적이 없기 때문에 충분히 깊이 파고드는 데 시간이 걸렸지만, 알 수 있었다고 생각합니다. :)

모든 전자 앱에는 메인(브라우저 창을 여는 역할)과 렌더러(Vue 앱이 실행되는 위치)의 2가지 이상의 프로세스가 있습니다.「 」를 사용하고 console.log코드 내에서 출력되는 위치는 코드라고 불리는 프로세스에 따라 달라집니다.console.log메인 프로세스에서 호출된 것은 터미널 창에만 표시됩니다(개발 모드에서 앱을 시작할 때 사용됨).console.log렌더러 프로세스에서 호출된 값은 Dev Tools에만 표시됩니다.

하지만 당신의 돌연변이의 로그는 둘 다에 나타납니다!그 말은 코드가 두 과정 모두에서 실행되어야 한다는 거죠, 그렇죠? 하지만 어떻게요?

전자 템플릿에는 vuex-electron을 사용하기 위한 옵션(프로젝트를 셋업할 때 켜야 함)이 있는 것 같습니다.특히,createSharedMutations플러그 인.메인 프로세스와 모든 렌더러 프로세스 간에 동일한 Vuex 저장소를 공유하기 위해 사용할 수 있습니다(기술적으로는 각 프로세스에 자체 저장소가 있지만 상태는 동기화됨).다음과 같이 동작합니다.

  1. (렌더러 프로세스에서) 액션을 실행한다.
  2. 렌더러 프로세스에서 작업이 취소되고(따라서 개발 도구에서 작업의 로그가 표시되지 않음) 대신 작업을 실행하도록 기본 프로세스에 알립니다.
  3. 이 동작(메인에서 실행 중)이 변환되면 메인 프로세스(Terminal - id 로그가 있는 첫 번째 스크린샷은 비어 있음)에서 변환 코드가 실행되며 payload(현재 새로 생성된 로그가 있음)가 실행됩니다.idA)는 JSON에 시리얼화되어(ipc-renderer 참조), 각 렌더러 프로세스에 전달되어 동일한 변환을 실행합니다(이 때문에 모든 스토어가 동기화된 상태로 유지됩니다).여기서 변환은 두 번째로 실행됩니다(DevTools 로그가 포함된 두 번째 스크린샷).item가지다id(A)는 이미 할당되어 있습니다만, 아이템 리스트에 없기 때문에, 코드에 의해서 새로운 것이 할당됩니다.id(B) 렉션 ( ( ( ( ( ( ( ( ( (
  4. id B에 .
  5. 저장하기 3.에서된 모든 하지만, 되는 변환은 과 함께 됩니다.idB. 이이 。 것을 해 줍니다.id B)되는 돌연변이는 다시 (B를 덮 ) C) 렌 음 음 음 음 음 음 음 음 음 음 시 시 시 시 시 시 with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with item itemid C

'비활성화'를 해제하는 입니다.createSharedMutationsconfig ( " " " " " " "에 있어야 합니다")/renderer/store/index.js) 된 스토어가 작성해야

언급URL : https://stackoverflow.com/questions/59052019/strange-behavior-of-vuex-mutations-in-electron-app-based-on-electron-vue

반응형