Как изменить значение 'value' в VueJS до того, как `$ emit ('input')` закончит его обновление - PullRequest
2 голосов
/ 30 апреля 2019

У меня есть вопрос о создании компонентов VueJS, которые можно использовать с v-model, которые используют базовые value prop и $emit('input', newVal).

props: {
  value: Array
},
methods: {
  moveIdToIndex (id, newIndex) {
    const newArrayHead = this.value
      .slice(0, newIndex)
      .filter(_id => _id !== id)
    const newArrayTail = this.value
      .slice(newIndex)
      .filter(_id => _id !== id)
    const newArray = [...newArrayHead, id, ...newArrayTail]
    return this.updateArray(newArray)
  },
  updateArray (newArray) {
    this.$emit('input', newArray)
  }
}

В приведенном выше примере кода, если я сделаю две модификациив быстрой последовательности они оба будут выполняться в «старом массиве» (неизмененном value prop).

moveIdToIndex('a', 4)
moveIdToIndex('b', 2)

Другими словами, мне нужно дождаться, пока value будетобновляется через $emit('input'), чтобы второй вызов moveIdToIndex использовал этот уже измененный массив.

Неправильное решение 1

Один обходной путь меняет updateArray на:

  updateArray (newArray) {
    return new Promise((resolve, reject) => {
      this.$emit('input', newArray)
      this.$nextTick(resolve)
    })
  }

и выполнить так:

await moveIdToIndex('a', 4)
moveIdToIndex('b', 2)

Но я не хочу этого делать, потому что мне нужно выполнить это действие с массивом идентификаторов и переместить их все в разные места нав то же время.И await IN значительно снизит производительность.

Плохое решение 2

Гораздо лучшее решение, которое я нашел, это просто сделать это:

  updateArray (newArray) {
    this.value = newArray
    this.$emit('input', newArray)
  }

Тогда я нене нужно ждать завершения $emit.

Тем не менее, в этом случае VueJS выдает консольную ошибку:

Избегайте непосредственного изменения опоры, так как значение будетбыть перезаписано всякий раз, когда родительский компонент перерисовывается.Вместо этого используйте данные или вычисляемое свойство, основанное на значении реквизита.Подставка изменена: «значение»

У кого-нибудь есть лучшее решение?

Ответы [ 3 ]

1 голос
/ 30 апреля 2019

OK.Это ваши параметры, насколько я понимаю, ваш сценарий использования и приложение.

Прежде всего, не изменяйте параметры напрямую, сохраняйте параметры внутри, а затем изменяйте это значение.

props: {
  value: Array
},
data() {
  return {
    val: this.value
  }
}

Если следующая модификация массива зависит от предыдущей модификации массива, вы не можете выполнять их одновременно.Но вам нужно, чтобы это произошло довольно быстро (я предполагаю, что вы хотите, чтобы пользователь почувствовал, что это происходит быстро).Что вы можете сделать, так это выполнить модификацию val внутри компонента и не делать ее зависимой от опоры.Переменная val инициализируется только при монтировании компонента.Таким образом, вы можете мгновенно изменить данные в пользовательском интерфейсе и позволить обновлению базы данных в фоновом режиме.

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

props: {
  value: Array
},
data () {
  return {val: this.value}
},
methods: {
  moveIdToIndex (id, newIndex) {
    const newArrayHead = this.val
      .slice(0, newIndex)
      .filter(_id => _id !== id)
    const newArrayTail = this.val
      .slice(newIndex)
      .filter(_id => _id !== id)
    const newArray = [...newArrayHead, id, ...newArrayTail]
    return this.updateArray(newArray)
  },
  updateArray (newArray) {
    this.val = newArray
    this.$emit('input', newArray)
  }
}

Это решение исправляетваша проблема и позволяет вам выполнить moveIdToIndex в быстрой последовательности, не ожидая ничего.

Теперь, если массив используется во многих местах приложения, лучше всего было бы переместить его в хранилище и использоватьэто как единая точка правды и обновите это и используйте это, чтобы обновить ваш компонент.Ваше состояние будет обновляться быстро, а не одновременно, а затем откладывать обновление базы данных на подходящее время.

0 голосов
/ 30 апреля 2019

Как насчет создания копии value?

moveIdToIndex (id, newIndex) {
    const valueCopy = [...this.value]
    const newArrayHead = this.valueCopy
      .slice(0, newIndex)
      .filter(_id => _id !== id)
    const newArrayTail = this.valueCopy
      .slice(newIndex)
      .filter(_id => _id !== id)
    const newArray = [...newArrayHead, id, ...newArrayTail]
    return this.updateArray(newArray)
0 голосов
/ 30 апреля 2019
  1. Emit сообщение родителю об изменении реквизита.
  2. Поместите watcher в реквизит (у ребенка) и поместите свой код для использования там нового значения.

Это удерживает ребенка от изменения данных, которыми он не владеет, и позволяет ему избегать использования nextTick.Теперь ваш код асинхронный и реактивный, не полагаясь на недетерминированные задержки.

...