Vue 子组件在第一页加载时不显示动态数据 [英] Vue child component not displaying dynamic data on first page load
问题描述
鉴于下面的代码,我的子组件警报在父安装函数中的任何代码之前触发.
Given the code below, my child component alerts trigger before any of the code in the Parent mounted function.
因此看起来孩子在数据准备好之前已经完成了初始化,因此在重新加载之前不会显示数据.
As a result it appears the child has already finished initialization before the data is ready and therefor won't display the data until it is reloaded.
当原始 JSON 显示在布局中的 v-card
内时,数据本身从 API 返回得很好.
The data itself comes back fine from the API as the raw JSON displays inside the v-card
in the layout.
我的问题是如何确保在加载子组件之前已准备好父级中请求的数据?我发现的任何内容都集中在使用 props 传递的静态数据上,但是当必须首先获取数据时,这似乎完全失败了.
My question is how can I make sure the data requested in the Parent is ready BEFORE the child component loads? Anything I have found focuses on static data passed in using props, but it seems this completely fails when the data must be fetched first.
在 Parent 的 mounted()
中,我有这个用于检索数据的代码.
Inside the mounted()
of the Parent I have this code which is retrieves the data.
const promisesArray = [this.loadPrivate(),this.loadPublic()]
await Promise.all(promisesArray).then(() => {
console.log('DATA ...') // fires after the log in Notes component
this.checkAttendanceForPreviousTwoWeeks().then(()=>{
this.getCurrentParticipants().then((results) => {
this.currentP = results
this.notesArr = this.notes // see getter below
})
获取父中数据的getter
The getter that retrieves the data in the parent
get notes() {
const newNotes = eventsModule.getNotes
return newNotes
}
我在父模板中的组件:
<v-card light elevation="">
{{ notes }} // Raw JSON displays correctly here
// Passing the dynamic data to the component via prop
<Notes v-if="notes.length" :notesArr="notes"/>
</v-card>
子组件:
...
// Pickingn up prop passed to child
@Prop({ type: Array, required: true })
notesArr!: object[]
constructor()
{
super();
alert(`Notes : ${this.notesArr}`) // nothing here
this.getNotes(this.notesArr)
}
async getNotes(eventNotes){
// THIS ALERT FIRES BEFORE PROMISES IN PARENT ARE COMPLETED
alert(`Notes.getNotes CALL.. ${eventNotes}`) // eventNotes = undefined
this.eventChanges = await eventNotes.map(note => {
return {
eventInfo: {
name: note.name,
group: note.groupNo || null,
date: note.displayDate,
},
note: note.noteToPresenter
}
})
}
...
我对 Vue 比较陌生,所以如果我忽略了一些基本的东西,请原谅我.我已经尝试修复它几天了但无法弄清楚所以非常感谢任何帮助!
I am relatively new to Vue so forgive me if I am overlooking something basic. I have been trying to fix it for a couple of days now and can't figure it out so any help is much appreciated!
推荐答案
如果你是 Vue 的新手,我真的建议你阅读它的整个文档以及你正在使用的工具 - vue-class-component(这是Vue插件添加的API,用于将Vue组件声明为类)
If you are new to Vue, I really recommend reading the entire documentation of it and the tools you are using - vue-class-component (which is Vue plugin adding API for declaring Vue components as classes)
因此,您应该将代码移动到 created()
,而不是使用 constructor()
生命周期钩子
So instead of using constructor()
you should move your code to created()
lifecycle hook
在这种情况下,这应该足以修复您的代码,但只是因为 Notes
组件的使用由 v-if="notes.length"
保护在父级中 - 只有在 notes
不是空数组
This should be enough to fix your code in this case BUT only because the usage of the Notes
component is guarded by v-if="notes.length"
in the Parent - the component will get created only after notes
is not empty array
这在很多情况下是不够的!
This is not enough in many cases!
created()
生命周期钩子(和data()
函数/钩子)只对每个组件执行一次.里面的代码是一次初始化.因此,当/如果父组件更改了notesArr
属性的内容(有时在将来),eventChanges
将不会更新.即使你知道 parent 永远不会更新 prop,请注意,出于性能原因,当使用v-for
或 使用v-if
>/v-else
- Vue 只是更新 props,而不是销毁现有组件和创建新组件.应用突然无缘无故地崩溃了......
created()
lifecycle hook (anddata()
function/hook) is executed only once for each component. The code inside is one time initialization. So when/if parent component changes the content ofnotesArr
prop (sometimes in the future), theeventChanges
will not get updated. Even if you know that parent will never update the prop, note that for performance reasons Vue tend to reuse existing component instances when possible when rendering lists withv-for
or switching between components of the same type withv-if
/v-else
- instead of destroying existing and creating new components, Vue just updates the props. App suddenly looks broken for no reason...
这是许多没有经验的用户都会犯的错误.你可以在这里找到很多关于 SO 的问题,比如我的组件不是响应式的";或如何强制我的组件重新渲染"有很多答案建议使用 :key
hack 或使用 watcher .... 有时可以工作,但几乎总是比正确的解决方案复杂得多
This is a mistake many unexperienced users do. You can find many questions here on SO like "my component is not reactive" or "how to force my component re-render" with many answers suggesting using :key
hack or using a watcher ....which sometimes work but is almost always much more complicated then the right solution
正确的解决方案是将您的组件(如果可以 - 有时不可能)编写为 纯组件(文章是针对 React 但原则仍然适用).在 Vue 中实现这一目标的非常重要的工具是 计算属性
Right solution is to write your components (if you can - sometimes it is not possible) as pure components (article is for React but the principles still apply). Very important tool for achieving this in Vue are computed propeties
所以,而不是引入 eventChanges
数据属性(其中 可能会或可能不会反应 - 这从您的代码中不清楚),您应该将其设置为直接使用 notesArr
道具的计算属性:
So instead of introducing eventChanges
data property (which might or might not be reactive - this is not clear from your code), you should make it computed property which is using notesArr
prop directly:
get eventChanges() {
return this.notesArr.map(note => {
return {
eventInfo: {
name: note.name,
group: note.groupNo || null,
date: note.displayDate,
},
note: note.noteToPresenter
}
})
}
现在每当 notesArr
属性被父级更改时,eventChanges
都会更新并且组件将重新渲染
Now whenever notesArr
prop is changed by the parent, eventChanges
is updated and the component will re-render
注意事项:
- 您过度使用了
async
.您的getNotes
函数不执行任何异步代码,因此只需将其删除即可. - 也不要混合使用
async
和then
- 这很容易混淆
- You are overusing
async
. YourgetNotes
function does not execute any asynchronous code so just remove it. - also do not mix
async
andthen
- it is confusing
要么:
const promisesArray = [this.loadPrivate(),this.loadPublic()]
await Promise.all(promisesArray)
await this.checkAttendanceForPreviousTwoWeeks()
const results = await this.getCurrentParticipants()
this.currentP = results
this.notesArr = this.notes
或:
const promisesArray = [this.loadPrivate(),this.loadPublic()]
Promise.all(promisesArray)
.then(() => this.checkAttendanceForPreviousTwoWeeks())
.then(() => this.getCurrentParticipants())
.then((results) => {
this.currentP = results
this.notesArr = this.notes
})
这篇关于Vue 子组件在第一页加载时不显示动态数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!