简体   繁体   English

Vue3:创建的钩子与数据字段中的对象实例化

[英]Vue3: Object instantiation in created hook vs data field

I'm migrating a project from Vue2 to 3, and trying to understand an error that I get when creating a field on component data.我正在将一个项目从 Vue2 迁移到 3,并试图了解在组件数据上创建字段时遇到的错误。 Using ToneJS, I can create a new Synth() either in the body of a method, or in the created hook, and call it in my playNote method.使用 ToneJS,我可以在方法的主体中或在 created 钩子中创建一个new Synth() ,并在我的playNote方法中调用它。 However, when the synth is defined as a field on data , I get the error below when the "Play" button is clicked.但是,当将合成器定义为data字段时,单击“播放”按钮时出现以下错误。

In Vue2 I had no problem like this.在 Vue2 中我没有这样的问题。 Wondering if someone can explain what is happening here?想知道是否有人可以解释这里发生了什么? Why does the created hook work but not the data field?为什么创建的钩子有效,但数据字段无效?

Thanks for any help with this!感谢您对此的任何帮助! The full text of the error:错误的全文:

runtime-core.esm-bundler.js?5c40:6568 [Vue warn]: Unhandled error during execution of native event handler at <Main onVnodeUnmounted=fn ref=Ref< Proxy {playNote: ƒ, …} > > at at warn @ runtime-core.esm-bundler.js?5c40:6568 logError @ runtime-core.esm-bundler.js?5c40:6742 handleError @ runtime-core.esm-bundler.js?5c40:6734 eval @ runtime-core.esm-bundler.js?5c40:6697 Promise.catch (async) callWithAsyncErrorHandling @ runtime-core.esm-bundler.js?5c40:6696 invoker @ runtime-dom.esm-bundler.js?830f:347 localhost/:1 Uncaught (in promise) DOMException runtime-core.esm-bundler.js?5c40:6568 [Vue 警告]:在 <Main onVnodeUnmounted=fn ref=Ref< Proxy {playNote: ƒ, …} >> at warn @ 处执行本机事件处理程序期间未处理的错误runtime-core.esm-bundler.js?5c40:6568 logError @ runtime-core.esm-bundler.js?5c40:6742 handleError @ runtime-core.esm-bundler.js?5c40:6734 eval @ runtime-core.esm -bundler.js?5c40:6697 Promise.catch (async) callWithAsyncErrorHandling @ runtime-core.esm-bundler.js?5c40:6696 invoker @ runtime-dom.esm-bundler.js?830f:347 localhost/:1 Uncaught (承诺)DOMException

<template>    
<div>      
<button v-on:click="playNote">Play</button>    
</div>  
</template>   
<script lang="ts">  
import { defineComponent } from "vue";      
import * as Tone from 'tone'  

export default defineComponent({          
  name: "Main",          
  data() {              
    return {  
      synth: new Tone.Synth().toDestination(), // this throws an error 
      playing: false, 
    }
  },          
  methods: {              
    async playNote(){  
      console.log('playNote'); // logs properly await Tone.start();          
      console.log('this.synth', this.synth); // synth object logs        
      this.synth.triggerAttackRelease('C4', '8n');                   
    
      // this works:            
      // const synth = new Tone.Synth().toDestination();        
      // synth.triggerAttackRelease('C4', '8n');              
    },          
  },   
  created() {     
    // this.synth = new Tone.Synth().toDestination() // this also works   
  }    
});      
</script>

In Vue 3, Vue use Proxy to track changes from the object (Vue 2 use Object.defineProperty ).在 Vue 3 中,Vue 使用Proxy来跟踪来自对象的更改(Vue 2 使用Object.defineProperty )。

When we return a plain JavaScript object from a component's data function, Vue will wrap that object in a Proxy with handlers for get and set.当我们从组件的 data 函数返回一个普通的 JavaScript 对象时,Vue 会将该对象包装在带有 get 和 set 处理程序的代理中。

From How Vue Tracks These Changes .Vue 如何跟踪这些变化

After debugging, I found that the error came from a file named get-native-context from standardized-audio-context package which will throw an error if it cannot find some context variable:调试后,我发现错误来自standardized-audio-context包中名为get-native-context的文件,如果找不到某些上下文变量,则会抛出错误:

export const createGetNativeContext = (contextStore) => {
    return (context) => {
        const nativeContext = contextStore.get(context); // contextStore is a WeakMap
        if (nativeContext === undefined) {
            throw createInvalidStateError();
        }
        return (nativeContext);
    };
};

The original file is here .原始文件在这里

So my guess is somewhere in the library store the Synth context object ( synth.context._context ) for later use.所以我的猜测是在库中的某个地方存储 Synth 上下文对象( synth.context._context )以备后用。 But the Synth context object has be changed to the Proxy.但是 Synth 上下文对象已经改为了 Proxy。 When it tries to get the context via contextStore.get(context) it will return undefined .当它尝试通过contextStore.get(context)获取contextStore.get(context) ,它将返回undefined

From your code:从您的代码:

created() {     
    this.synth = new Tone.Synth().toDestination()
}

This works because of this.synth is just a normal object not reactive (Proxy).这是因为this.synth只是一个没有反应性的普通对象(代理)。

If you don't need the synth object to be reactive your code is fine both in method and created hook.如果您不需要synth对象是反应式的,那么您的代码在方法和创建的钩子中都很好。 But if you want it to be reactive you have to wrap it in some way.但是,如果您希望它具有反应性,则必须以某种方式包装它。

For example:例如:

...
  data() {
    return {
      synth: () => new Tone.Synth().toDestination()
    }
  },
  methods: {
    async playNote() {
      this.synth().triggerAttackRelease('C4', '8n')
    }
  }
...

This is not a good example as synth will create every time it's used.这不是一个很好的例子,因为synth每次使用时都会创建。 JSFiddle JSFiddle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM