Vue 子组件在第一页加载时不显示动态数据 [英] Vue child component not displaying dynamic data on first page load

查看:137
本文介绍了Vue 子组件在第一页加载时不显示动态数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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)

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

因此,您应该将代码移动到 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!

  1. created() 生命周期钩子(和 data() 函数/钩子)只对每个组件执行一次.里面的代码是一次初始化.因此,当/如果父组件更改了 notesArr 属性的内容(有时在将来),eventChanges 将不会更新.即使你知道 parent 永远不会更新 prop,请注意,出于性能原因,当使用 v-for使用 v-if>/v-else - Vue 只是更新 props,而不是销毁现有组件和创建新组件.应用突然无缘无故地崩溃了......
  1. created() lifecycle hook (and data() function/hook) is executed only once for each component. The code inside is one time initialization. So when/if parent component changes the content of notesArr prop (sometimes in the future), the eventChanges 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 with v-for or switching between components of the same type with v-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 函数不执行任何异步代码,因此只需将其删除即可.
  • 也不要混合使用 asyncthen - 这很容易混淆
  • You are overusing async. Your getNotes function does not execute any asynchronous code so just remove it.
  • also do not mix async and then - 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆