首页 > 解决方案 > Vuex 存储更新但 DOM 没有

问题描述

我浏览了有关此主题的所有帖子,但似乎找不到答案。我的 Vuex 商店更新正常,但 DOM 不是。

这是正在发生的事情的屏幕截图

我有一个getterreturnAmazonCredentials

returnAmazonCredentials(state) {
  return state.amazonCredentials
},

我像这样导入它:

computed: {
  ...mapGetters('amazonCredentials', [
    'returnAmazonCredentials',
]),

returnAmazonCredentials是一个数组,所以我在我的 DOM 中使用它v-for

v-for="(cred, index) in returnAmazonCredentials"

而且我还使用gettersandsetters来更新数组中的元素。这是一个例子

sellerId: {
  get() {
    return this.returnAmazonCredentials.merchant_id
  },
  set(value) {
    this.$set(this.returnAmazonCredentials[this.credIndex], 'merchant_id', value)
  }
},

this.credIndex在单击元素时设置

当我想从returnAmazonCredentials数组中删除一个元素时,我这样做:

this.returnAmazonCredentials.splice(index, 1)

Vuex 存储完美更新,而 DOM 仍然显示存储中不再存在的旧数据。我试过了:

this.$nextTick() as well as this.$forceUpdate()

没有运气..我在哪里误入歧途?

编辑:这是我组件中的所有代码

<template>
  <v-container fluid v-resize="getHeight">
    <v-row align="center" justify="center">
      <v-col cols="12">
        <v-card 
          class="purple_top"
          color="#e1bee7"
        >
          <v-container>
            <v-row>
              <v-col cols="1" align="start">
                <v-icon class="my_dark_purple_text pretty_icon mt-2" x-large>info</v-icon>
              </v-col>

              <v-col cols="11" align="start">
                <h1 class="text-h6 mont bold pt-3 pb-2">You will not be charged until after you've entered all your credentials below</h1>
                <h1 class="text-subtitle-1 mont font-weight-bold">After your 7 day free trial your costs will be:</h1>
                  <v-list class="purple_list" dense>
                    <v-list-item>
                      <v-list-item-icon class="mr-2">
                        <v-icon class="my_dark_purple_text">info</v-icon>
                      </v-list-item-icon>
                      <v-list-item-content>
                        <div class="text-body-1 mont">$25/month for the first marketplace</div>
                      </v-list-item-content>
                    </v-list-item>
                    
                    <v-list-item>
                      <v-list-item-icon class="mr-2">
                        <v-icon class="my_dark_purple_text">info</v-icon>
                      </v-list-item-icon>
                      <v-list-item-content>
                        <div class="text-body-1 mont">$20/month for each additional marketplace</div>
                      </v-list-item-content>
                    </v-list-item>
                  </v-list>
              </v-col>
            </v-row>
          </v-container>
        </v-card>
      </v-col>
    </v-row>

    <v-row>
      <v-col cols="8">
        <v-card 
          color="#f1e7df"
          id="devIds"
        >
          <v-card-title>
            <v-icon class="my_dark_purple_text">vpn_key</v-icon>
            <h1 class="text-h6 oswald my_dark_purple_text pl-2">DEVELOPMENT IDS</h1>
          </v-card-title>
          <v-container>
            <v-row>
              <v-col cols="6" class="ml-10">
                <h1 class="text-h6 mont">US, Canada, Mexico</h1>
              </v-col>
              <v-col cols="5">
                <h1 class="text-h6 mont">UK and the EU</h1>
              </v-col>
            </v-row>

            <v-row>
              <v-col cols="3" class="ml-10">
                <v-text-field readonly solo :value="us" class="mont"></v-text-field>
              </v-col>
              <v-col cols="3">
                <v-btn height="48px" class="my_dark_purple_btn ml-n7" @click="copyCreds(us)">Copy</v-btn>
              </v-col>

              <v-col cols="3" class="">
                <v-text-field readonly solo :value="eu" class="mont"></v-text-field>
              </v-col>
              <v-col cols="2">
                <v-btn height="48px" class="my_dark_purple_btn ml-n7" @click="copyCreds(eu)">Copy</v-btn>
              </v-col>
            </v-row>

            <v-row>
              <v-col cols="6" class="ml-10">
                <h1 class="text-h6 mont">Australia</h1>
              </v-col>
              <v-col cols="5">
                <h1 class="text-h6 mont">Japan</h1>
              </v-col>
            </v-row>

            <v-row>
              <v-col cols="3" class="ml-10">
                <v-text-field readonly solo :value="us" class="mont"></v-text-field>
              </v-col>
              <v-col cols="3">
                <v-btn height="48px" class="my_dark_purple_btn ml-n7" @click="copyCreds(australia)">Copy</v-btn>
              </v-col>

              <v-col cols="3" class="">
                <v-text-field readonly solo :value="eu" class="mont"></v-text-field>
              </v-col>
              <v-col cols="2">
                <v-btn height="48px" class="my_dark_purple_btn ml-n7" @click="copyCreds(japan)">Copy</v-btn>
              </v-col>
            </v-row>
          </v-container>
        </v-card>
      </v-col>

      <v-col cols="4">
        <v-card 
          color="#d9d6e1"
          :height="matchingHeights + 'px'"
        >
          <v-container fluid fill-height>
            <v-row class="pt-2">
              <v-col cols="12" justify="center" align="center">
                <a href="https://youtu.be/-iWlFyX0254" target="_blank">
                  <v-img 
                    src="how.png"
                    max-width="153px"
                    contain
                  ></v-img>
                </a>
              </v-col>
            </v-row>
            <v-row>
              <v-col cols="12">
                <h1 class="mont text-h5 text-center">Do I retrieve my US Amazon credentials?</h1>
              </v-col>
            </v-row>
            
            <v-row>
              <v-divider class="mx-4"></v-divider>
            </v-row>

            <v-row class="pt-2">
              <v-col cols="12" justify="center" align="center">
                <a href="https://youtu.be/p4RwqegRc9s" target="_blank">
                  <v-img 
                    src="how.png"
                    max-width="153px"
                    contain
                  ></v-img>
                </a>
              </v-col>
            </v-row>
            <v-row>
              <v-col cols="12">
                <h1 class="mont text-h5 text-center">Do I retrieve my Amazon credentials outside of the US?</h1>
              </v-col>
            </v-row>
          </v-container>
        </v-card>
      </v-col>

    </v-row>

    <p>credentials are {{ returnAmazonCredentials }}</p>

    <v-row
      v-for="(cred, index) in returnAmazonCredentials"
      :key="index"
    >
      <v-col cols="12">
          <v-card 
            color="#e9daea"
          >
            <v-card-title>
              <v-icon class="my_dark_purple_text">language</v-icon>
              <h1 class="text-h6 oswald my_dark_purple_text pl-2">ENTER YOUR AMAZON CREDENTIALS BELOW</h1>
            </v-card-title>

            <v-container>
              <v-form>
              <v-row>
                <v-col cols="6">
                  
                  <v-row>
                    <v-col cols="12">
                      <v-text-field
                        color="#6a0080"
                        label="Amazon Seller Id"
                        prepend-icon="person"
                        v-model="sellerId"
                        @click="setIndex(index)"
                        :rules="[() => !!returnAmazonCredentials[credIndex]['merchant_id'] || 'Please provide your Amazon seller id', sellerIdValidation(!!returnAmazonCredentials[credIndex]['merchant_id']) ]"
                      ></v-text-field> 
                    </v-col>
                  </v-row>

                  <v-row>
                    <v-col cols="12">
                      <v-select
                        :items="marketplaces"
                        label="Select your Amazon Marketplace"
                        color="#6a0080"
                        prepend-icon="map"
                        v-model="marketplace"
                        @click="setIndex(index)"
                        :rules="[() => !!returnAmazonCredentials[credIndex]['marketplace'] || 'Please select your Amazon marketplace', marketValidation(!!returnAmazonCredentials[credIndex]['marketplace']) ]"
                      ></v-select>              
                    </v-col>
                  </v-row>

                  <v-row>
                    <v-col cols="12">
                      <v-text-field
                        color="#6a0080"
                        label="Amazon Auth Token"
                        prepend-icon="https"
                        v-model="authToken"
                        @click="setIndex(index)"
                        :rules="[() => !!returnAmazonCredentials[credIndex]['auth_token'] || 'Please provide your Amazon auth token', authTokenValidation(!!returnAmazonCredentials[credIndex]['auth_token']) ]"
                      ></v-text-field>                
                    </v-col>
                  </v-row>

                </v-col>
                
                <v-col cols="1">
                  <v-divider vertical></v-divider>
                </v-col>

                <v-col cols="5">

                  <v-row class="mt-1">
                    <v-btn 
                      color="#68007d"
                      outlined
                      block
                      x-large
                      :disabled="_.some(errors, (element) => _.includes(element, index))"
                      @click="saveMarketplace"
                      :loading="saveLoading"
                    >
                      <v-icon
                        left
                      >
                        check_circle
                      </v-icon>
                      SAVE THIS MARKETPLACE
                    </v-btn>
                  </v-row>

                  <v-row class="mt-11">
                    <v-btn 
                      block
                      x-large
                      outlined
                      color="#388E3C"
                      @click="addMarketplace"
                    >
                      <v-icon
                        left
                      >
                        add_circle
                      </v-icon>
                      ADD ANOTHER MARKETPLACE
                    </v-btn>
                  </v-row>

                  <v-row class="mt-11">
                    <v-btn 
                      block
                      x-large
                      outlined
                      color="#B71C1C"
                      :disabled="returnAmazonCredentials.length == 1"
                      @click="removeMarketplace(index)"
                    >
                      <v-icon
                        left
                      >
                        remove_circle
                      </v-icon>
                      REMOVE MARKETPLACE
                    </v-btn>
                  </v-row>

                </v-col>
              </v-row>
              </v-form>
              <v-row v-if="(returnAmazonCredentials.length - 1) == index">
                <v-col cols="12">
                  <v-btn 
                    class="white--text"
                    color="#68007d"
                    block
                    x-large
                    @click="sendCreds"
                    :loading="finishedLoading"
                    :disabled="errors.length > 0"
                    id="custom-disabled"
                  >
                    FINISHED
                  </v-btn>                  
                </v-col>
              </v-row>
            </v-container>
          </v-card>
      </v-col>
    </v-row>


      <v-dialog 
        v-model="failDialog" 
        max-width="600px"
        persistent
      >
        <v-card>
          <v-card-title>
            <span class="title font-weight-bold">Oh snap! It looks like your credentials are incorrect</span>
          </v-card-title>

          <v-card-text>
            <v-row>
              <v-col cols="12">
                <h1
                  class="subtitle-1"
                  style="color: black !important;"
                >Amazon let us know the following error:</h1>
              </v-col>
            </v-row>

            <v-row
              :class="spacing"
              v-for="(reason, index) in failReasons"
              :key="reason.marketplace"
            >
              <v-col cols="12">
                <h1
                  class="subtitle-1"
                >Your credentials failed in this marketplace: <strong>{{ reason.marketplace }}</strong></h1>
              </v-col>
              <v-col cols="12" class="mt-n5">
                <h1
                  class="subtitle-1"
                >For this reason: <strong>{{ reason.reason }}</strong></h1>
              </v-col>

              <v-col 
                cols="12" 
                justify="center" 
                align="center"
              >
                <a :href="whichVideoToShow(reason.marketplace)" target="_blank">
                  <v-img 
                    src="blank_how.png"
                    max-width="100px"
                    contain
                  ></v-img>
                </a>
              </v-col>

              <v-col cols="12" class="mt-n5">
                <h1 class="subtitle-1 text-center">Do I retrieve my Amazon credentials?</h1>
              </v-col>

            <v-divider class="mx-4 mt-3"></v-divider>

            </v-row>

          </v-card-text>

          <v-card-actions class="">
            <v-spacer></v-spacer>
            <v-btn color="#68007d" large class="white--text" @click="closeDialog">I UNDERSTAND</v-btn>
          </v-card-actions> 

        </v-card>
      </v-dialog>


  </v-container>
</template>

<script>
import axios from 'axios';
import { mapGetters, mapActions } from 'vuex'

export default {
  data: function() {
    return {
      failDialog: false,
      australia: "6078-0648-3237",
      us: "7531-9706-4825",
      eu: "4048-6340-0484",
      japan: "1447-5438-8862",
      matchingHeights: 295,
      marketplaces:[
        { text: 'Australia', value: "A39IBJ37TRP1C6" },
        { text: 'Canada', value: "A2EUQ1WTGCTBG2" },
        { text: 'France', value: "A13V1IB3VIYZZH" },
        { text: 'Germany', value: "A1PA6795UKMFR9" },
        { text: 'Italy', value: "APJ6JRA9NG5V4" },
        { text: 'Japan', value: "A1VC38T7YXB528" },
        { text: 'Mexico', value: "A1AM78C64UM0Y8" },
        { text: 'Spain', value: "A1RKKUPIHCS9HS" },
        { text: 'United Kingdom', value: "A1F83G8C2ARO7P" },
        { text: 'United States', value: "ATVPDKIKX0DER" },          
      ],
      credIndex: 0,
      errors: [],
      finishedLoading: false,
      saveLoading: false,
      amazonError: '',
      failReasons: [],
    };
  },
  async mounted() {
    await this.getRemoteAmazonCredentials()
  },
  computed: {
    ...mapGetters('amazonCredentials', [
      'returnAmazonCredentials',
    ]),
    sellerId: {
      get() {
        return this.returnAmazonCredentials.merchant_id
      },
      set(value) {
        this.$set(this.returnAmazonCredentials[this.credIndex], 'merchant_id', value)
      }
    },
    marketplace: {
      get() {
        return this.returnAmazonCredentials.marketplace
      },
      set(value) {
        this.$set(this.returnAmazonCredentials[this.credIndex], 'marketplace', value)
      }      
    },
    authToken: {
      get() {
        return this.returnAmazonCredentials.auth_token
      },
      set(value) {
        this.$set(this.returnAmazonCredentials[this.credIndex], 'auth_token', value)
      }        
    }
  },
  methods: {
    ...mapActions('amazonCredentials', [
      'getRemoteAmazonCredentials',
      'testRemoteAmazonCredentials',
      'removeAmazonCredential'
    ]),
    setIndex(index) {
      this.credIndex = index
    },
    getHeight() {
      var devCard = document.getElementById("devIds");
      this.matchingHeights = devCard.offsetHeight;
    },
    copyCreds(country) {
      this.$clipboard(country);
    },
    sellerIdValidation(value) {
      if(value){
        _.pull(this.errors, `${this.credIndex}-id`)
      }
      else {
       if(!_.includes(this.errors, `${this.credIndex}-id`)) {
        this.errors.push(`${this.credIndex}-id`)
       }
      }
      return true
    },
    marketValidation(value) {
      if(value){
        _.pull(this.errors, `${this.credIndex}-market`)
      }
      else {
       if(!_.includes(this.errors, `${this.credIndex}-market`)) {
        this.errors.push(`${this.credIndex}-market`)
       }
      }
      return true
    },
    authTokenValidation(value) {
      if(value){
        _.pull(this.errors, `${this.credIndex}-auth`)
      }
      else {
       if(!_.includes(this.errors, `${this.credIndex}-auth`)) {
        this.errors.push(`${this.credIndex}-auth`)
       }
      }
      return true
    },
    addMarketplace() {
      this.returnAmazonCredentials.push({})
    },
    removeMarketplace(index) {
      this.removeAmazonCredential(index)
      this.credIndex = 0
    },
    async sendCreds() {
      this.failReasons = []
      this.finishedLoading = true
      let me = this.returnAmazonCredentials
      let response = await this.testRemoteAmazonCredentials()
      this.addRemoveTestFailure(response)      
    },
    async saveMarketplace() {
      this.failReasons = []
      this.saveLoading = true
      let response = await this.testRemoteAmazonCredentials()
      this.addRemoveTestFailure(response)
    },
    addRemoveTestFailure(response) {
      response.forEach(element => {
        if(element.result == "fail") {
          this.failDialog = true
          let failure = {
            reason: element.reason,
            marketplace: element.marketplace
          }
          this.failReasons.push(failure)
        }
      })
      this.saveLoading = false
      this.finishedLoading = false
    },
    closeDialog() {
      this.failDialog = false
      this.saveLoading = false
    },
    whichVideoToShow(marketplace) {
      if(marketplace == "United States" || marketplace == "Mexico" || marketplace == "Canada") {
        return 'https://youtu.be/-iWlFyX0254'
      }
      else {
        return 'https://youtu.be/p4RwqegRc9s'
      }
    },
    spacing() {
      if(this.failReasons.length >= 1) {
        return mt-n4
      }
    }
  }
};
</script>


<style scoped>
@import '../../styles/global_styles.css';

#custom-disabled.v-btn--disabled {
    background-color: rgba(104,0,125,.5) !important;
    color: white !important;
}

</style>

我确实mutation在我的商店中添加了这个以删除元素

removeCredential: (state, payload) => {
  state.amazonCredentials.splice(payload, 1)
},

这是我在组件本身中更新的方法:

removeMarketplace(index) {
  this.removeAmazonCredential(index)
  this.credIndex = 0
},

我在哪里发送要从凭证数组中删除的索引。

但是是的,我已经在组件本身中这样做了,并且得到了相同的效果。在 DOM 未更新时更新数据..

标签: vue.jsvuex

解决方案


您应该发送一个删除该项目的操作:

   sellerId: {
      get() {
        return this.returnAmazonCredentials.merchant_id
      },
      set(value) {
        this.$store.dispatch('removeCredential',this.credIndex)
      }
    },

店铺 :

  mutations: {
    REMOVE_CREDENTIAL (state,index) {
      state.amazonCredentials.splice(index, 1)
    }
  },
  actions: {
    removeCredential(context,index) {
      context.commit('REMOVE_CREDENTIAL',index)
    }

推荐阅读