首页 > 解决方案 > 通过 $set 更改对象属性给出:“TypeError: Cannot read property 'call' of undefined”

问题描述

首先,你好。

我对 Web 开发和 Vue.js 或 Javascript 比较陌生。我正在尝试实现一个系统,使用户能够上传图片和视频并为其投票。一般来说,整个系统都工作。但是因为我从服务器获取了所有信息,所以用于显示文件的对象 + 它们的统计信息不是反应性的。我试图改变我将对象的属性从 "file['votes'] ) await data.data().votes" 更改为 "file.$set('votes', await data.data().votes )”。但是现在我得到了 TypeError: Cannot read property 'call' of undefined Error。我不知道为什么会发生这种情况,或者这个错误甚至意味着什么。在互联网上搜索了很多之后,我找不到任何有同样问题的人。我的方法一定有遗传上的错误。

如果有人能给我解释正在发生的事情或者能给我一个更好的方法来处理我的问题,我将非常感激。

提前感谢任何愿意尝试的人。这是我更改的代码部分:

async viewVideo() {
  this.videoURLS = []
  this.videoFiles = []
  this.videoTitels = []
  var storageRef = firebase.storage().ref();
  var videourl = []
  console.log("try")
  var listRef = storageRef.child('User-Videos/');
  var firstPage = await listRef.list({
    maxResults: 100
  });
  videourl = firstPage
  console.log(videourl)
  if (firstPage.nextPageToken) {
    var secondPage = await listRef.list({
      maxResults: 100,
      pageToken: firstPage.nextPageToken,
    });
    videourl = firstPage + secondPage

  }
  console.log(this.videoURLS)
  if (this.videoURLS.length == 0) {
    await videourl.items.map(async refImage => {

      var ii = refImage.getDownloadURL()
      this.videoURLS.push(ii)
    })

    try {
      await this.videoURLS.forEach(async file => {

        var fale2 = undefined
        await file.then(url => {
          fale2 = url.substring(url.indexOf("%") + 3)
          fale2 = fale2.substring(0, fale2.indexOf("?"))
        })
        await db.collection("Files").doc(fale2).get().then(async data => {
          file.$set('titel', await data.data().titel)
          file.$set('date', await data.data().date)
          if (file.$set('voted', await data.data().voted)) {
            file.$set('voted', [])
          }
          file.$set('votes', await data.data().votes)
          if (file.$set('votes', await data.data().votes)) {
            file.$set('votes', 0)
          }
          await this.videoFiles.push(file)
          this.uploadDate = data.data().date
          console.log(this.videoFiles)
          this.videoFiles.sort(function(a, b) {
            return a.date - b.date;
          })
        })
      })
    } catch (error) {
      console.log(error)
    }
  }
},
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

标签: javascriptvue.jswebsettypeerror

解决方案


首先,file.$set('votes', await data.data().votes)是使用错误的语法。应该是this.$set(file, 'votes', data.data().votes)。我猜第二个data返回data()一个带有投票作为属性的对象。

您在这里不需要使用 await 。await db.collection("Files").doc(fale2).get().then(async data => {....

您已经在.then此处以块的形式使用了 Promise。异步等待和then/catch块基本上做同样的事情。这是一个或另一个。

请查看这篇精彩的帖子,其中介绍了如何在 javascript 中处理异步代码。现在了解 javascript 的异步特性非常重要。

有很多东西可以选择,现在我的重点是从你的代码中删除多余的或可能无法使其工作的东西。我不关注逻辑。有了更多信息,我可能会对逻辑进行必要的编辑。

我会在代码中留下我觉得有必要的注释

async viewVideo() {
  this.videoURLS = []
  this.videoFiles = []
  this.videoTitels = []
  var storageRef = firebase.storage().ref();
  var videourl = '' // videourl should be initialised as a string 
  console.log("try")
  var listRef = storageRef.child('User-Videos/');
  var firstPage = listRef.list({  // the await here isn't necessary as this function isn't expected to return a promise(isn't asynchronous) to the best of my knowledge.
    maxResults: 100
  });
  videourl = firstPage
  console.log(videourl)
  if (firstPage.nextPageToken) {
    var secondPage = listRef.list({  // same as above
      maxResults: 100,
      pageToken: firstPage.nextPageToken,
    });
    videourl = firstPage + secondPage // videourl is a string here

  }
  console.log(this.videoURLS)
  if (this.videoURLS.length == 0) {
    videourl.items.map(async refImage => { //videourl is acting as an object here (something seems off here) - please explain what is happening here
// again await is not needed here as the map function does not return a promise

      var ii = refImage.getDownloadURL()
      this.videoURLS.push(ii)
    })

    try {
      this.videoURLS.forEach(file => { // await here is not necessary as the forEach method does not return a promise

      // The 'async' keyword is not necessary here. It is required to use the await keyword and due to the database call here, ordinarily it wouldn't be out of place, but you deal with that bit of asynchronous code using a `.then` block. It's `async-await` or `.then` and never both.

        var fale2 = undefined
        file.then(url => { // await is not necessary here as you use `.then`
        // Also, does `file` return a promise? That's the only thing I can infer from `file.then`. It looks odd.
          fale2 = url.substring(url.indexOf("%") + 3)
          fale2 = fale2.substring(0, fale2.indexOf("?"))
        })
         db.collection("Files").doc(fale2).get().then(data => { // await and async not necessary due to the same reasons outlined above
          this.$set(file, 'titel', data.data().titel) // correct syntax according to vue's documentation - https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

          this.$set(file, 'date', data.data().date)
          if (this.$set(file, 'voted', data.data().voted)) { // I don't know what's going on here, I will just correct the syntax. I am not focused on the logic at this point
            this.$set(file, 'voted', [])
          }
          this.$set(file, 'votes', data.data().votes)
          if (this.$set(file, 'votes', data.data().votes)) {
            this.$set(file, 'votes', 0)
          }
          this.videoFiles.push(file) // await not necessary here as the push method does not return a promise and also is not asynchronous

          this.uploadDate = data.data().date
          console.log(this.videoFiles)
          this.videoFiles.sort(function(a, b) {
            return a.date - b.date;
          })
        })
      })
    } catch (error) {
      console.log(error)
    }
  }
},

就像我在开头所说的那样,第一次尝试并不是为了让逻辑起作用。那里发生了很多我不明白的事情。我专注于删除冗余代码和纠正语法错误。如果提供更多细节,我也许可以查看逻辑。


推荐阅读