Vue子组件在第一页加载时不显示动态数据
Posted
技术标签:
【中文标题】Vue子组件在第一页加载时不显示动态数据【英文标题】:Vue child component not displaying dynamic data on first page load 【发布时间】:2021-10-28 19:18:34 【问题描述】:鉴于下面的代码,我的子组件警报在父挂载函数中的任何代码之前触发。
因此,在数据准备好之前,孩子似乎已经完成了初始化,因此在重新加载之前不会显示数据。
当原始 JSON 显示在布局中的 v-card
内时,数据本身可以从 API 中正常返回。
我的问题是如何确保在子组件加载之前,父组件中请求的数据已准备好?我发现的所有内容都集中在使用 props 传入的静态数据上,但是当必须首先获取数据时,这似乎完全失败了。
在父级的mounted()
中,我有这段代码用于检索数据。
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
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 比较陌生,所以如果我忽略了一些基本的东西,请原谅我。我已经尝试修复它几天了,但无法弄清楚,因此非常感谢任何帮助!
【问题讨论】:
看来您使用的是vue-class-component ....正确? 【参考方案1】:如果您是 Vue 新手,我真的建议您阅读它的整个文档以及您正在使用的工具 - vue-class-component(这是 Vue 插件添加 API 用于将 Vue 组件声明为类)
-
Caveats of Class Component - Always use lifecycle hooks instead of
constructor
因此,您应该将代码移动到created()
lifecycle hook,而不是使用constructor()
在这种情况下,这应该足以修复您的代码,但只是因为 Notes
组件的使用由父级中的 v-if="notes.length"
保护 - 只有在 notes
不是空数组后才会创建组件
这在很多情况下是不够的!
created()
生命周期钩子(和 data()
函数/钩子)仅对每个组件执行一次。里面的代码是一次性初始化。因此,当/如果父组件更改 notesArr
道具的内容(有时在将来),eventChanges
将不会得到更新。即使你知道 parent 永远不会更新 prop,请注意,出于性能原因,Vue 倾向于在使用 v-for
或 switching between components of the same type 和 v-if
/v-else
渲染列表时尽可能重用现有组件实例 - 而不是破坏现有的并创建新组件,Vue 只是更新道具。应用突然看起来无缘无故坏了...
这是许多没有经验的用户都会犯的错误。您可以在这里找到很多关于 SO 的问题,例如“我的组件没有反应性”或“如何强制我的组件重新渲染”,许多答案建议使用 :key
hack 或使用观察者 ....有时可以工作但几乎总是比正确的解决方案复杂得多
正确的解决方案是将组件编写为pure components(如果可以 - 有时是不可能的)(文章适用于 React,但原则仍然适用)。在 Vue 中实现这一点的非常重要的工具是 computed propeties
因此,不要引入 eventChanges
数据属性(might or might not be reactive - 这从您的代码中不清楚),您应该将其设为直接使用 notesArr
属性的计算属性:
get eventChanges()
return this.notesArr.map(note =>
return
eventInfo:
name: note.name,
group: note.groupNo || null,
date: note.displayDate,
,
note: note.noteToPresenter
)
现在每当 notesArr
属性被父级更改时,eventChanges
就会更新并且组件将重新渲染
注意事项:
您过度使用async
。您的 getNotes
函数不会执行任何异步代码,因此只需将其删除即可。
也不要混用 async
和 then
- 这会令人困惑
要么:
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
)
Great learning resource
【讨论】:
非常感谢这位米哈尔。你给了我一些很好的指导,让我继续前进。我认为因为我正在实例化一个类,所以可以使用constructor()
函数,就像普通的 JS 一样。但是,是的,我同意,vue-class-component
插件改变了一切。我将根据您的建议尝试重构整个组件,希望它能解决问题。再次感谢您的时间和精力。以上是关于Vue子组件在第一页加载时不显示动态数据的主要内容,如果未能解决你的问题,请参考以下文章