Vue родительский компонент не перерисовывается при изменении вычисляемых свойств - PullRequest
1 голос
/ 04 марта 2020

У меня есть User-Select компонент, который упаковывает v-select . Эта работа компонентов заключается в получении списка пользователей в качестве типов пользователей и позволяет пользователю выбрать одного или нескольких пользователей. Вот код для этого компонента.

<template>
  <div>
    <v-select
      id="recipients"
      name="recipients"
      :options="options"
      label="name"
      multiple
      @search="onSearch"
      v-model="selectedVal"
    />
  </div>
</template>

<script>
import vSelect from 'vue-select'
import axios from 'axios'
import _ from 'lodash'
export default {
  name: 'UserSelect',
  components: {
    'v-select': vSelect
  },
  props: {
    value: {
      type: Array
    }
  },
  data() {
    return {
      options: []
    }
  },
  computed: {
    selectedVal: {
      get() {
        return this.value
      },
      set(val) {
        //this.value = val
        this.$emit('input', val)
      }
    }
  },
  methods: {
    onSearch(search, loading) {
      loading(true)
      this.search(loading, search, this)
    },
    setSelected: function(val) {
      this.$emit('input', val)
    },
    search: _.debounce((loading, search, vm) => {
      axios
        .post('searchPeople', { search }, { useCredentails: true })
        .then(res => {
          vm.options = res.data
          loading(false)
        })
    }, 350)
  }
}
</script>

<style lang="scss" scoped>
@import url('https://unpkg.com/vue-select@latest/dist/vue-select.css');
</style>

Как вы можете видеть, у меня есть v-модель, связанная с вычисляемым свойством, которое генерирует событие ввода. Также мое имя собственности value. Следовательно, я ожидаю, что родительский компонент, который использует этот компонент UserEvent, сможет v-моделировать.

Edit elastic-fast-t3pti

В родительском компоненте у меня есть вычисляемое свойство, к которому я v-моделировал выбранное значение. Вот код.

<template>
  <div>
    <b-modal id="editMessage" :title="title" :static="true">
      <form id="newMessageForm" class="row">
        <div class="col-md-12">
          <div class="form-group row">
            <label for="to" class="col-sm-3 col-form-label">To:</label>
            <user-select
              class="col-sm-7"
              style="padding-left: 0px; padding-right: 0px"
              v-model="editedMessage.recipients"
            />
          </div>
          <div class="form-group row">
            <label for="subject" class="col-sm-3 col-form-label"
              >Subject:</label
            >
            <input
              id="subject"
              name="subject"
              type="text"
              class="form-control col-sm-7"
              :value="editedMessage.messageSubject"
            />
          </div>
          <div class="form-group row">
            <label for="date" class="col-sm-3 col-form-label"
              >Schedule for later :
            </label>
            <input
              type="checkbox"
              class="form-control col-sm-7"
              v-model="scheduleForLater"
              id="scheduleCheckBox"
            />
          </div>
          <div class="form-group row" v-if="scheduleForLater">
            <label for="date" class="col-sm-3 col-form-label"
              >Scheduled Date:</label
            >
            <datetime
              v-model="editedMessage.sentDate"
              type="datetime"
              class="col-sm-17"
              input-class="form-control col-sm-15"
              input-id="date"
            />
          </div>
          <div class="form-group row">
            <label for="body" class="col-sm-3 col-form-label">Message:</label>
            <textarea
              id="body"
              name="body"
              type="text"
              rows="10"
              class="form-control col-sm-7"
              :value="editedMessage.messageBody"
            ></textarea>
          </div>
        </div>
      </form>

      <template v-slot:modal-footer="{ hide }">
        <!-- Emulate built in modal footer ok and cancel button actions -->

        <b-button size="sm" variant="light" @click="hide()">
          Cancel
        </b-button>
        <b-button
          size="sm"
          variant="secondary"
          @click="
            sendMessage(true)
            hide()
          "
        >
          Save Draft
        </b-button>
        <b-button
          size="sm"
          variant="primary"
          @click="
            sendMessage(false)
            hide()
          "
        >
          Send
        </b-button>
      </template>
    </b-modal>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import UserSelect from '@/components/UserSelect.vue'
import axios from 'axios'
export default {
  name: 'NewMessage',
  components: {
    'user-select': UserSelect
  },
  data() {
    return {
      options: [],
      scheduleForLater: false
    }
  },
  mounted() {},
  computed: {
    ...mapState({
      openMessage: state => state.message.openMessage,
      messageAction: state => state.message.messageAction
    }),
    editedMessage: {
      get() {
        if (this.messageAction === 'new') {
          return this.newMessage()
        } else if (this.messageAction === 'reply') {
          let openMessageClone = Object.assign({}, this.openMessage)
          // make sender as the recipient.
          return Object.assign(openMessageClone, {
            messageSubject: 'RE: ' + this.openMessage.messageSubject,
            recipients: [
              {
                name: this.openMessage.sender.name,
                id: this.openMessage.sender.id
              }
            ]
          })
        } else {
          let openMessageClone = Object.assign({}, this.openMessage)
          return Object.assign(openMessageClone, {
            messageSubject: 'FW: ' + this.openMessage.messageSubject
          })
        }
      },
      set(val) {
        this.$emit('input', val)
      }
    },
    title() {
      if (this.messageAction === 'new') {
        return 'New'
      } else if (this.messageAction === 'reply') {
        return 'Reply'
      } else {
        return 'Forward'
      }
    }
  },
  methods: {
    newMessage() {
      return {
        messageBody: '',
        messageSubject: '',
        recipients: [],
        sender: {}
      }
    },
    sendMessage(saveOrUpdateDraft) {
      var url = ''
      var message = {
        recipients: this.editedMessage.recipients.map(x => x.id),
        subject: this.editedMessage.messageSubject,
        body: this.editedMessage.messageBody,
        sentDate: this.scheduleForLater ? this.editedMessage.sentDate : null,
        id: ['editDraft', 'viewScheduled'].includes(this.messageAction)
          ? this.editedMessage.messageId
          : null
      }
      // id indiciates message id of draft message if one was opened.
      if (saveOrUpdateDraft) {
        // if no changes have been made to an opened draft, or the draft is completely empty for a new or existing draft , just go back.
        if (message.id) {
          url = `updateDraft`
        } else {
          url = 'saveNewDraft'
        }
      } else {
        if (message.id) {
          url = `sendSavedMessage`
        } else {
          url = 'sendMessage'
        }
      }
      axios
        .post(`eventdirect/${url}`, message, {
          withCredentials: true
        })
        .then(response => {
          if (url.includes('Draft') && this.messageAction === 'viewScheduled') {
            this.$store.dispatch('sent/moveToDraft', response.data)
          } else if (url.includes('Draft')) {
            this.$store.dispatch('drafts/updateDraft', response.data)
          } else {
            // else part is sending a message or scheduling a draft.
            if (this.messageAction === 'editDraft') {
              this.$store.dispatch('drafts/deleteDraft', response.data)
            }
            // if we are sending an existing scheduled messsage , just update the sent vuex store , so that the message moves from scheduled to sent bucket.
            if (this.messageAction === 'viewScheduled') {
              this.$store.dispatch('sent/updateMessage', response.data)
            } else {
              this.$store.dispatch('sent/addSentItem', response.data)
            }
          }
        })
        .catch(() => {
          // TODO , add a qtip here to notify user , this message should be sent later.
          // messages in draft store with target , should be posted to the target
          this.$store.dispatch('drafts/updateDraft', {
            ...message,
            target: url
          })
        })
    }
  }
}
</script>

Теперь я могу видеть в vue dev-инструментах, что вычисленные значения в этом NewMessage компоненте изменены. Однако этот компонент не выполняет повторную визуализацию, и выбранные значения не передаются компоненту UserSelect до тех пор, пока я не переключусь, установите флажок для последующего изменения, что приведет к изменению данных компонентов, и это приведет к тому, что компонент Vue внезапно начнет показывать выбранные значения.

Что здесь происходит. В реактивности Vue есть кое-что, что я не могу понять здесь.

Спасибо в ожидании. Вы можете попробовать здесь или нажать на кнопку редактирования песочницы выше, чтобы просмотреть и отредактировать код.

Чтобы попробовать, нажмите на ссылку Vue Сообщение, затем нажмите «Ответить», затем введите «Test» и затем выберите «Test User» из выпадающего списка. Выбранный пользователь не будет отображаться, пока вы не установите флажок - Расписание позже.

PS: в компоненте UserSelect, в установщике вычисляемого свойства selectedVal, если я вручную установлю значение значения свойства ( просто раскомментировав строку 39 (которая прокомментирована прямо сейчас), все работает отлично. Тем не менее, я получаю предупреждение, что свойство не должно быть установлено напрямую. Поскольку я излучаю входное событие, родительский компонент должен изменить свою v-модель и выполнить повторную визуализацию, в результате чего дочерний компонент должен выполнить повторную визуализацию. Пожалуйста, поправьте меня, если мое понимание неверно. Еще раз проблема заключается в том, что v-модель родительского компонента изменяется, но не перерисовывается.

enter image description here

...