首页 > 解决方案 > Vue子组件在第一页加载时不显示动态数据

问题描述

鉴于下面的代码,我的子组件警报在父挂载函数中的任何代码之前触发。

结果,看起来孩子在数据准备好之前已经完成了初始化,因此在重新加载之前不会显示数据。

数据本身可以从 API 中很好地返回,因为原始 JSON 显示在v-card布局中。

我的问题是如何确保在子组件加载之前,Parent 中请求的数据已准备好?我发现的所有内容都集中在使用 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 比较陌生,所以如果我忽略了一些基本的东西,请原谅我。我已经尝试修复它几天了,但无法弄清楚,所以非常感谢任何帮助!

标签: javascriptvue.jscomponentsvue-props

解决方案


如果您是 Vue 新手,我真的建议您阅读它的整个文档以及您正在使用的工具 - vue-class-component(这是 Vue 插件添加 API 用于将 Vue 组件声明为类)

  1. 类组件的注意事项 - 始终使用生命周期钩子而不是constructor

constructor()因此,您应该将代码移动到生命周期挂钩而不是使用created()

在这种情况下,这应该足以修复您的代码,但只是因为组件的使用在 Parent 中Notes受到保护- 只有在不是空数组后才会创建组件v-if="notes.length"notes

这在很多情况下是不够的!

  1. created()生命周期钩子(和data()函数/钩子)只对每个组件执行一次。里面的代码是一次性初始化的。因此,当/如果父组件更改notesArrprop 的内容时(有时在将来),eventChanges则不会更新。即使您知道 parent 永远不会更新 prop,请注意,出于性能原因,Vue 倾向于在使用 / 渲染列表或在相同类型的组件之间切换时尽可能重用现有组件实例-而v-for不是破坏现有组件并创建新组件, Vue 只是更新道具。应用程序突然看起来无缘无故坏了......v-ifv-else

这是许多没有经验的用户会犯的错误。您可以在这里找到很多关于 SO 的问题,例如“我的组件不是反应式”或“如何强制我的组件重新渲染”,其中有很多答案建议使用:keyhack 或使用 watcher ....有时有效,但几乎总是更多复杂然后正确的解决方案

正确的解决方案是将您的组件(如果可以 - 有时不可能)编写为纯组件(文章适用于 React,但原则仍然适用)。在 Vue 中实现这一点的非常重要的工具是计算属性

因此,不要引入eventChangesdata 属性(它可能是反应性的,也可能不是反应性的 - 这在您的代码中不清楚),您应该将其设为notesArr直接使用 prop 的计算属性:

get eventChanges() {
   return this.notesArr.map(note => {
     return {
       eventInfo: {
         name: note.name,
         group: note.groupNo || null,
         date: note.displayDate,
       },     
       note: note.noteToPresenter
     }
   })
}

现在,每当notesArr父级更改 prop 时,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
  })

很棒的学习资源


推荐阅读