Vue.js/Axios — Дублировать результаты в списке. Имеет уникальные ключи в v-для

#vuejs2 #axios #v-for

#vuejs2 #аксиос #v-для

Вопрос:

У меня есть два других варианта использования v-for в отдельных компонентах. Они также иногда выдают ошибки. Все три вызова v-for завершаются с помощью v-if/else. Вот код, который создает повторяющиеся ключевые ошибки и дважды отображает данные:

Учетная запись Dashboard.vue

 <tbody>
  <tr v-if="!residents.length" class="table-info">
    <td class="text-center">
      <p>
        No residents on record. 
      </p>
    </td>
  </tr>
  <template v-else>
    <tr is="AccountResidentList"
      v-for="resident in residents"
      v-bind:key="'resident-list-'   resident.id"
      v-bind:first_name="resident.first_name"
      v-bind:last_name="resident.last_name"
      v-bind:dob="resident.dob | date_formatted"
      >
    </tr>
  </template>
</tbody>
 

Обратите внимание на попытку уникального идентификатора при привязке ключа.

Вот посмотрите на дочерний компонент

ProviderAccountList.vue

 <template>
  <tr class="AccountResidentList">
    <td>
      {{ this.$attrs.id }}
    </td>
    <td>
      {{ this.$attrs.first_name }} {{ this.$attrs.last_name }}
    </td>
    <td>
      {{ this.$attrs.dob }}
    </td>
    <td>
      <button @click="toResidentProfile({account_id, id})" class="btn btn-sm btn-purple btn-with-icon">
        <div class="ht-25">
         <span class="icon wd-25"><i class="fa fa-eye"></i></span>
         <span class="pd-x-10">view</span>
       </div>
      </button>
    </td>
    <!--TODO: Add view profile button-->
  </tr>
</template>

 <script>
 import Axios from "axios";
 import router from "../../router";
 import { mapGetters } from "vuex";
 import moment from "moment";

 export default {
  name: "AccountResidentList",
  computed: {
    ...mapGetters['Resident', {
      resident: 'getResident'
    }]
  },
  filters: {
    date_formatted: (date) => {
      return moment(date).format('MMMM Do, YYYY');
    }
  },
  methods: {
    toResidentProfile(account_id, resident_id) {
      router.push(`/accounts/${account_id}/residents/${resident_id}`)
    }
  },
};
 </script>
 <style scoped></style>
 

Мой вызов Axios выглядит так:

Account.js (vuex-модуль с пространством имен)

   async retrieveAccount(context, account_id) {
      // Axios.defaults.headers.common['Authorization'] = 'Bearer '   window.$cookies.get('jwt')
      let response
      let valid_id = window.$cookies.get('valid_id');
      response = await Axios.get(`http://localhost:3000/api/v1/providers/${valid_id}/accounts/${account_id}`, { headers: { 'Authorization': 'Bearer '   window.$cookies.get('jwt') } })
      .then((response) => {
        let account = response.data.locals.account;
        let account_address = response.data.locals.account_address;
        let residents = response.data.locals.residents;
        // set Account
        context.dispatch('Account/setId', account.id, {root: true});
        context.dispatch('Account/setProviderId', account.provider_id, {root: true});
        .
        .
        .

        // set AccountAddress
        // !Array.isArray(array) || !array.length
        if (account.address) {
          context.dispatch('Account/setAddressId', account_address.id, {root: true});
          context.dispatch('Address/setId', account_address.id, {root: true});
        .
        .
        . 

        // set AccountResidents
        // !Array.isArray(array) || !array.length
        residents.forEach(resident => {
          if (resident) {
            // Add object to parent's list
            context.dispatch('Account/setResidents', resident, {root: true});         // Set attr values for object
            context.dispatch('Resident/setId', resident.id, {root: true});
            .
            .
            .
            (remaining attrs removed for brevity)
          }
        })

        router.push(`/providers/${account.provider_id}/accounts/${account_id}`);
      })
      .catch(function(error) {
        console.log(error);
      })
 

Примечание: действие учетной записи #setResidents просто вызывает мутатор, который добавляет одного резидента к общему количеству списка.

i.e state.list.push(resident)

Я зарегистрировал ответ на консоль и могу подтвердить, что данные не отправляются дважды (или более) из моего вызова Axios.

консоль.результаты журнала

Я просмотрел и попытался выполнить следующее, но безрезультатно:

Наконец, следует упомянуть, что я пробовал варианты использования / неиспользования template для переноса списка, включая / не включая цикл for в template , и т.д..

Не ожидал, что повторение коллекции будет настолько утомительным.

Я упускаю из виду что-то очевидное?

Обновление: что сработало для меня

Мне нужен был доступ к resident.id кроме того, идентификатор, объявленный в paren, выглядит как индекс. Итак, вот посмотрите, что устранило повторяющиеся ошибки рендеринга и позволило мне получить доступ к идентификатору резидента даже после исправления ошибки с дубликатами ключей:

 <template v-else>
  <tr is="AccountResidentList"
    v-for="(resident, id) in residents"
    v-bind:key="id"
    v-bind:id="resident.id"
    v-bind:first_name="resident.first_name"
    v-bind:last_name="resident.last_name"
    v-bind:dob="resident.dob | date_formatted"
  >
  </tr>
</template>
 

Еще раз спасибо @Billal Begueradj за помощь!

Комментарии:

1. Попробуйте: v-for="(resident, id) in residents" :key="'id"

2. @Billal Begueradj 1 за быстрый ответ! Это работает для всех моих итераций. Если вы разместите это как ответ, я приму. Большое спасибо 🙂

Ответ №1:

Что касается меня, я подозреваю, что внутри residents есть записи, которые имеют один и тот же идентификатор. Поэтому мы должны найти способ преодолеть эту проблему. Мы можем дать ему эффективную попытку следующим образом:

 <tr 
  is="AccountResidentList"
  v-for="(resident, id) in residents"
  :key="id"
  // rest of your code
 

Комментарии:

1. Ошибка с моими дубликатами ключей исчезла, но для вашей точки ввода с тем же идентификатором мой список теперь отображается дважды. На иллюстрации (изображение console.log) показаны уникальные идентификаторы для каждого присутствующего резидента. Есть ли причина, по которой это изменится при пинге моего сервера?

2. Ошибка с дубликатом ключей исчезла. Мой список дублировался до тех пор, пока я не разрешил моему привязанному ключу выступать в качестве идентификатора. До исправления двойного рендеринга я также привязывал идентификатор, вызывая дублирование. Удаление этого и использование ключа вместо этого возвращает желаемые результаты.

3. Трудно следовать коду в Account.js , особенно без тестируемого кода, который я могу попробовать. Тем не менее, попробуйте: 1. В AccountDashboard.vue заменить is="AccountResidentList" на class="AccountResidentList" . 2. ProviderAccountList.vue удалите ` <tr class=»AccountResidentList»>` и </tr> @sirramongabriel Вы можете отменить мой ответ, если он не поможет, так что, надеюсь, кто-то еще мог бы взглянуть на ваш код глубже