vue.jsvuejs3piniaant-design-vue

Using pinia state in Vue3 Watch() then pinia state become Synchronization Update


After excuted once saveChange() ,pinia's state workType & workRegionState become Synchronization Update when i change my checkbox , Even though I didn't excute saveChange() again .

export const usePorfileStore = defineStore('userProfile', () => {
    const workType = ref<workType>({ surveyor: false, designer: true, decorator: true });
    const workRegionState = ref<workRegionState>({
      indeterminate: false,
      checkAll: true,
      checkedList: ['北台灣', '中台灣', '南台灣', '東台灣', '台灣外島']
    });

    const updataWorkType = (type: workType) => {
      workType.value = type;
    };
    const updataWorkRegionState = (state: workRegionState) => {
      workRegionState.value = state;
    };
    return {
      workType,
      workRegionState,
      updataWorkType,
      updataWorkRegionState,
    };
  },
  {
    persist: true
  }
);

I skiped import Part in the following code block , It's unrelated in this question.

<script setup lang="ts">
const profileStore = usePorfileStore();
const avatarURLChanged = ref<boolean>(false);
const workTypeChanged = ref<boolean>(false);
const workRegionChanged = ref<boolean>(false);
const isChange = ref<boolean>(false);
const workTypeCheck = reactive<workType>({
  surveyor: profileStore.workType.surveyor,
  designer: profileStore.workType.designer,
  decorator: profileStore.workType.decorator
});
const localWorkType = reactive<workType>({
  surveyor: profileStore.workType.surveyor,
  designer: profileStore.workType.designer,
  decorator: profileStore.workType.decorator
});
const workRegionCheck = reactive<workRegionState>({
  indeterminate: profileStore.workRegionState.indeterminate,
  checkAll: profileStore.workRegionState.checkAll,
  checkedList: profileStore.workRegionState.checkedList
});

const updateLocalData = () => {
  localWorkType.surveyor = profileStore.workType.surveyor;
  localWorkType.designer = profileStore.workType.designer;
  localWorkType.decorator = profileStore.workType.decorator;
};
const resetChange = () => {
  workTypeChanged.value = false;
  workRegionChanged.value = false;
  isChange.value = false;
};

const saveChange = () => {
  console.log('saveChange');
  if (avatarURLChanged.value) {
    uploadToS3();
  }
  if (workTypeChanged.value || workRegionChanged.value) {
    AccountService.updateWork({
      workType: workTypeCheck,
      workRegion: workRegionToObj(workRegionCheck.checkedList)
    });
    profileStore.updataWorkType(workTypeCheck);
    profileStore.updataWorkRegionState(workRegionCheck);
  }
  updateLocalData();
  resetChange();
};

watch([() => workTypeCheck, () => workRegionCheck.checkedList], () => {
    workTypeChanged.value = !isEqual(workTypeCheck, localWorkType);
    workRegionChanged.value = !isEqual(workRegionCheck.checkedList, profileStore.workRegionState.checkedList);
    isChange.value = workTypeChanged.value || workRegionChanged.value;
  },
  { deep: true }
);
</script>

<template>

<a-flex>
        <a-checkbox v-model:checked="workTypeCheck.designer"
                    class="font-size-middle font-weight-bold text-color-secondary"> 室內設計服務
        </a-checkbox>
        <a-checkbox v-model:checked="workTypeCheck.decorator"
                    class="font-size-middle font-weight-bold text-color-secondary">裝潢施工服務
        </a-checkbox>
      </a-flex>
      <a-typography-text strong class="font-size-middle font-weight-bold text-color-primary" content="服務地區" />
      <a-checkbox v-model:checked="workRegionCheck.checkAll" :indeterminate="workRegionCheck.indeterminate"
                  @change="onCheckAllChange" class="font-size-middle font-weight-bold text-color-secondary"> 全台灣
      </a-checkbox>
      <a-checkbox-group v-model:value="workRegionCheck.checkedList" :options="workRegionOptions">
        <template #label="{label}">
          <span class="font-size-middle font-weight-bold text-color-secondary">{{ label }}</span>
        </template>
      </a-checkbox-group>
      <a-button v-if="isChange" type="primary" class="full-size font-size-large" @click="saveChange">
        儲存變更
      </a-button>
      <a-button v-else type="primary" disabled class="full-size font-size-large">儲存變更</a-button>

</template>

Solution

  • The profileStore.workType will be a proxy that equal to workTypeCheck when you call function updataWorkType, so I add a clone function to create a new object instead using workTypeCheck directly.

       const saveChange = () => {
          console.log('saveChange');
          if (avatarURLChanged.value) {
            uploadToS3();
          }
          if (workTypeChanged.value || workRegionChanged.value) {
            AccountService.updateWork({
              workType: workTypeCheck,
              workRegion: workRegionToObj(workRegionCheck.checkedList)
            });
            profileStore.updataWorkType(clone(workTypeCheck));
            profileStore.updataWorkRegionState(clone(workRegionCheck));
          }
          updateLocalData();
          resetChange();
        };
        function clone(val) {
            return JSON.parse(JSON.stringify(val))
        }