Реквизиты дочерних компонентов VueJs не обновляются мгновенно
У меня есть настройка родительского/дочернего компонентов, где родитель загружает данные с сервера и передает их дочерним элементам через реквизиты. В дочернем я хотел бы создать экземпляр календаря jQuery с некоторыми данными, которые он получает от родителя.
Чтобы дождаться данных перед настройкой календаря, я транслирую событие в родительском элементе, в котором у меня есть настройка прослушивателя событий для дочернего элемента.
Слушатель запускается в дочернем элементе, но если я this.$log('theProp')
, то он undefined. Тем не менее, если я проверяю компоненты с помощью VueJs devtools, между ними существует родительское/дочернее отношение, и ребенок получает поддержку в то же время.
Предел определяется для ребенка как динамический prop :the-prop="theProp"
. Поскольку ребенок действительно получает опору в конце, я предполагаю, что моя настройка верна, но, похоже, какая-то задержка. Родитель устанавливает реквизит в функции возврата вызова ajax и снова: он работает, просто с небольшой задержкой. Кажется, что.
Я также попробовал зарегистрировать прослушиватель watch
на опоре в дочернем элементе, чтобы я мог настроить календарь и убедиться, что там есть опора. Тем не менее, прослушиватель часов срабатывает, но this.$log('theProp')
по-прежнему undefined.
Если я передаю данные вместе с широковещательным вызовом, например this.$broadcast('dataLoaded', theData)
, ребенок получает его просто отлично. Но это кажется неправильным делать это таким образом, поскольку я в основном создаю свой собственный обработчик.
Я не отправляю какой-либо код, потому что компоненты довольно большие, и VueJs devtools говорят мне, что ситуация с родителем/ребенком работает.
Мне не хватает информации? Есть ли небольшая задержка между установкой значения в родительском и получающем его ребенке? Каким будет подходящий способ дождаться родительских данных у ребенка?
Обычно, когда вы просто выводите данные в шаблон, время не имеет большого значения, поскольку данные привязаны к шаблону. Но в этом случае мне действительно нужны данные для настройки календаря, или это будет неправильно.
Спасибо.
изменить 1: здесь jsfiddle: https://jsfiddle.net/dr3djo0u/1/
Кажется, он подтверждает, что данные недоступны сразу после трансляции. Тем не менее, наблюдатель работает, хотя я мог почти поклясться, что иногда this.$log('someData')
возвращал undefined
, когда я настраивал этот тестовый файл.
Но я думаю, что моя проблема может быть где-то в другом месте, я посмотрю сегодня вечером, теперь у меня нет проекта.
edit 2: выполнил еще несколько тестов. Моя проблема заключалась в том, что а) прослушиватели событий, похоже, не получают данные мгновенно, и б) я также пытался запустить календарь в обратном вызове route.data
, если someData
уже был (например, при поступлении с родителя), но это обратный вызов маршрута вызывается до того, как компонент готов, поэтому он тоже не работает.
Мое решение теперь следующее:
// works when the child route is loaded directly and parent finishes loading someData
watch: {
someData() {
this.initCalendar();
}
},
// works when navigating from parent (data already loaded)
ready() {
if (this.someData && this.someData.length) {
this.initCalendar()
}
}
Ответы
Ответ 1
Насколько я знаю, вам не нужны события для передачи данных от родителя к ребенку.
Все, что вам нужно, в дочернем компоненте: props: ['theProp']
И при использовании дочернего компонента в родительском: <child :theProp="someData"></child>
Теперь, где бы вы ни изменяли someData
в родительском someData
, дочерний компонент будет реагировать соответствующим образом.
Вам не нужны события, вам не нужно "смотреть", вам не нужно "готово".
Например: после вызова AJAX в родительском "ready" вы загружаете некоторые данные:
// at the parent component
data: function () {
return {
someData: {}
}
},
ready: function () {
var vm = this;
$.get(url, function(response) {
vm.someData = response;
});
}
Теперь вам не нужно больше ничего передавать данные ребенку. Это уже у ребенка как theProp
!
Что вам действительно нужно сделать, так это иметь в дочернем theProp
нечто, реагирующее на изменения данных, в своем собственном theProp
.
Либо в интерфейсе:
<div v-if="theProp.id > 0">
Loaded!
</div>
Или в коде JavaScript:
// at the child component
computed: {
// using a computed property based on theProp value
awesomeDate: function() {
if (!this.theProp || (this.theProp.length === 0)) {
return false;
}
if (!this.initialized) {
this.initCalendar();
}
return this.theProp.someThing;
}
}
Обновление 1
В родителе вы также можете сделать дочерний объект условно:
<child v-if="dataLoaded" :theProp="someData"></child>
Установите для dataLoaded
значение true, только если данные доступны.
Обновление 2
Или, возможно, ваша проблема связана с предупреждением об обнаружении изменений
Может быть, вы создаете новое свойство в объекте...
vm.someObject.someProperty = someValue
... когда ты должен сделать...
vm.$set('someObject.someProperty', someValue)
... среди других "предостережений".
Обновление 3
В VueJS 2 вы не ограничены шаблонами. Вы можете использовать функцию рендеринга и кодировать наиболее сложную логику рендеринга.
Обновление 4 (относительно OP edit 2)
Может быть, вы можете упасть ready
и использовать immediate
вариант, так что ваша инициализация в одном месте:
watch: {
someData: {
handler: function (someData) {
// check someData and eventually call
this.initCalendar();
},
immediate: true
}
}
Ответ 2
решение (тестирование в порядке)
В дочернем компоненте, использующем только данные props
, нет необходимости переназначать значения props
data
, это приведет к ошибке обновления!
vue дочерний компонент реквизит обновление ошибка и решение
![enter image description here]()
https://forum.vuejs.org/t/child-component-is-not-updated-when-parent-component-model-changes/18283?u=xgqfrms