执行调度程序刷新期间未处理的错误。这可能是 Vue 内部错误

Unhandled error during execution of scheduler flush. This is likely a Vue internals bug

我在 Vue.js 中创建幻灯片时遇到以下错误:

[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next 
  at <Anonymous key=1 > 
  at <Anonymous pager="true" options= {initialSlide: 1, speed: 400} > 
  at <Anonymous fullscreen=true > 
  at <IonPage isInOutlet=true registerIonPage=fn<registerIonPage> > 
  at <Product Details ref=Ref< Proxy {…} > key="/products/1" isInOutlet=true  ... > 
  at <IonRouterOutlet> 
  at <IonApp> 
  at <App>
Uncaught (in promise) DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
    at insert (webpack-internal:///./node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js:222:16)
    at mountElement (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:3958:9)
    at processElement (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:3899:13)
    at patch (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:3819:21)
    at componentEffect (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4312:21)
    at reactiveEffect (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:71:24)
    at effect (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:46:9)
    at setupRenderEffect (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4277:89)
    at mountComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4235:9)
    at processComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4195:17)

如果我添加硬编码的幻灯片,它不会显示任何错误。但是,如果我使用 v-for 循环动态添加幻灯片,则会显示上述错误。

我已按以下方式添加幻灯片:

这是模板:

  <ion-slides pager="true" :options="slideOpts">
    <ion-slide v-for="image in product.product_images" v-bind:key="image.id">
      <h1>Slide 1</h1>
    </ion-slide>
  </ion-slides>

这是脚本:

export default {
  name: "Product Details",
  components: {
    IonContent,
    IonHeader,
    IonPage,
    IonTitle,
    IonToolbar,
    IonSlides,
    IonSlide,
  },
  data() {
    return {
      product: {},
    };
  },
  setup() {
    // Optional parameters to pass to the swiper instance. See http://idangero.us/swiper/api/ for valid options.
    const slideOpts = {
      initialSlide: 1,
      speed: 400,
    };
    return { slideOpts };
  },
  mounted: function () {
    fetch("http://localhost:4000/api/products/" + this.$route.params.id, {
      method: "get",
    })
      .then((response) => {
        return response.json();
      })
      .then((jsonData) => {
        this.product = jsonData;
        // console.log(jsonData.product_images);
      });
  },
};

我在代码中做错了什么?

可以说,这个错误消息可以改进。

该错误是由于尝试使用 v-for 迭代不可迭代对象(在您的情况下 undefined)引起的。具体来说,在 mount() returns 中进行的调用之前,product.product_imagesundefined,因为您将 product 初始化为空对象。

Vue 2 风格解决方案

  • product.product_image实例化为可迭代的:
//...
  data: () => ({ 
    product: { product_images: [] }
  })

或在模板中提供一个空数组作为回退:

<ion-slide v-for="image in product.product_images || []" v-bind:key="image.id">
  <h1>Slide 1</h1>
</ion-slide> 

或者在 v-for 的父级上放置一个 v-if:

<ion-slides pager="true" :options="slideOpts" v-if="product.product_images">
  ...
</ion-slides>

Vue 3 风格解决方案

通过给它一个 async setup 函数,使整个 ProductDetails 组件暂停。在setup函数中,调用获取产品。
概念验证:

//...
async setup() {
  const product = await fetch("http://localhost:4000/api/products/" + 
    this.$route.params.id, {
      method: "get",
    }).then(r => r.json());
  return { product }
}

现在将 <product-details> 放入 <Suspense><template #default>,提供后备模板(将在 <Suspense> 解析其中找到的所有异步组件时呈现默认模板):

<Suspense>
  <template #default>
    <product-details></product-details>
  </template>
  <template #fallback>
    Product is loading...
  </template>
</Suspense>

使用 <Suspense> 的优点(和优雅)在于父级不需要知道尚未呈现标记的实际条件。它只是等待所有悬而未决的组件解决。
简而言之,使用 <Suspense> 您不再需要使用 v-ifs 将渲染逻辑硬编码到模板中并在包装器上明确指定条件。每个异步子组件都包含自己的条件,并且它向父组件宣布的只是:我完成了。全部完成后,它们就会被渲染。

还有 运行 当 hook 格式不正确时(createdmounted 等)也会出现此错误。在我的例子中,created 是一个对象而不是一个函数。

差:

created: { /* some code */ }

好:

created() { /* some code */ }
// or...
created: function() { /* some code */ }

能否更改组件名称?

export default 

  name: "Product Details" ... <= here

这为我修复了这个错误。

错误:

describe('App', () => {
  
  it('test 1', () => {
    const wrapper = shallowMount(Component)
    expect(wrapper.find('h2').text()).toEqual("my text")
  })

  it('test 2', () => {
    const wrapper = shallowMount(Component)
    expect(wrapper.find('h3').text()).toEqual("my othertext")
  })

})

没有 :

describe('App', () => {

  const wrapper = shallowMount(Component)
  
  it('test 1', () => {
    expect(wrapper.find('h2').text()).toEqual("my text")
  })

  it('test 2', () => {
    expect(wrapper.find('h3').text()).toEqual("my othertext")
  })

})