Unhandled error during execution of native event handler vue

Version 3.2.26 Reproduction link sfc.vuejs.org/ Steps to reproduce Create an @click handler Generate an error in the actual handler Observe that Vue issues a warning "Unhandled error during ex...

@adamreisnz

Version

3.2.26

Reproduction link

sfc.vuejs.org/

Steps to reproduce

  1. Create an @click handler
  2. Generate an error in the actual handler
  3. Observe that Vue issues a warning «Unhandled error during execution of native event handler»

What is expected?

For the actual error to be surfaced/logged/exposed to make debugging easier

What is actually happening?

The warning doesn’t contain any meaningful information and makes debugging challenging.


I can’t seem to reproduce this in the SFC playground, as I see the actual error surfacing there (e.g. Cannot read properties of undefined (reading ‘defaultPrevented’)), but when I do something similar in my app Vue keeps reporting the warning «Unhandled error during execution of native event handler» and the actual error is not shown or logged.

@LinusBorg

You must have a problem with your project setup, as this is what I see:

image

…and you see a stack trace in the playground as well.

Feel free to open a new issue here (or maybe in the Vue CLI repo, depending on your setup?) when you have a runnable reproduction repository.

Or ask for help in the community at chat.vuejs.org

@adamreisnz

My bad, you were right this was environmental. Turned out the event default was being prevented in the unhandledrejection listener with event.preventDefault()

Sorry for the noise, will leave this up in case someone else stumbles upon a similar issue.

@BrunoRicci

My bad, you were right this was environmental. Turned out the event default was being prevented in the unhandledrejection listener with event.preventDefault()

Sorry for the noise, will leave this up in case someone else stumbles upon a similar issue.

I’m facing the same issue and cannot seem to solve it. I get the same error over and over.

my html element has this attribute: @click="componentClicked"
and the method is in the «methods» object at the «script» section of the vue SFC.

componentClicked:(event)=>{ event.preventDefault(); console.log('Line clicked', event); this.$emit('line-click'); }

The componentClicked method works fine, and the «event» value is properly printed in the console. Apparently that component’s line this.$emit('line-click'); is the problem, this is the actual error I get, plus the warning you also had.
imagen

@BrunoRicci

My bad, you were right this was environmental. Turned out the event default was being prevented in the unhandledrejection listener with event.preventDefault()
Sorry for the noise, will leave this up in case someone else stumbles upon a similar issue.

I’m facing the same issue and cannot seem to solve it. I get the same error over and over.

my html element has this attribute: @click="componentClicked" and the method is in the «methods» object at the «script» section of the vue SFC.

componentClicked:(event)=>{ event.preventDefault(); console.log('Line clicked', event); this.$emit('line-click'); }

The componentClicked method works fine, and the «event» value is properly printed in the console. Apparently that component’s line this.$emit('line-click'); is the problem, this is the actual error I get, plus the warning you also had. imagen

Well, I finally found my mistake; I was calling «this» from an arrow function and not from the function itself… thus, «this» wasn’t accessible. I came up with this kind of error once and spent hours dealing with it, but this time I recalled about it and instantly realized.

I hope it will be useful for anyone who is perhaps facing the same issue.

@zhuhanyuguluguluzhu

What problem does this feature solve?

According to the documentation, when using Options API with TypeScript, complex props can be validated by using the PropType utility:

import {defineComponent, PropType} from 'vue';

interface Person {
    name: string;
}

export default defineComponent({
    props: {
        person: {
            type: Object as PropType<Person>,
            required: true,
        },
    },
});

This props declaration is verbose because you are effectively typing each prop twice: first you say it’s an Object, then you say the Object is in fact a Person.

If your prop has a type like type Foo = 'food' | number | null, things are even harder.

With the <script setup> way and the Composition API, we have the defineProps compiler macro, which is extremely clear and concise:

const props = defineProps<{
    person: Person;
}>();

I’m aware that the compiler macro is available only with <script setup>, which has an additional processing step where this macro is replaced with the actual prop declaration, which then feeds the «invisible» setup() method.

Now, in my not-so-fertile imagination, without knowing the underlying code, I imagine a better prop declaration for the Options API as being a generic parameter for the defineComponent call, something like:

export default defineComponent<{
    person: Person,
}>({

});

Is something like this technically possible? To keep backwards compatiblity, maybe another API like definePropComponent()?

It would be greatly useful to have a pure TypeScript declaration in Options API, like we have with the Composition API, since it would enforce the correct props declaration.

What does the proposed API look like?

A defineComponent() accepting a generic parameter to be taken as props. Emit declarations are actually pretty good already.

If backwards compatibility is an issue, a new API which would accept these generic parameters, something like definePropComponent().

I wanted to use the Toast component from PrimeVue library and I also wanted to create a nice re-usable service for it but I am getting this error. This doesn’t seem to be a problem if I don’t try to extract a separate service for the Toast notification.

But I do want to call useToast() from inside my custom service and not directly in component’s setup function.

I am using Vue 3.2.25 with Vite.js 2.9.9 and the latest version of PrimeVue

[Vue warn]: inject() can only be used inside setup() or functional components.
[Vue warn]: Unhandled error during execution of native event handler 
  at <App>

Uncaught Error: No PrimeVue Toast provided!
    at useToast (usetoast.esm.js:8:15)
    at Proxy.showToast (toastService.js:4:19)
    at _createElementVNode.onClick._cache.<computed>._cache.<computed> (App.vue:4:21)
    at callWithErrorHandling (runtime-core.esm-bundler.js:155:22)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:164:21)
    at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js:369:13)

Here is a CodeSandbox link: https://codesandbox.io/s/prime-vue-toast-issue-owcio8?file=/src/services/toastService.js

Here is my main.js

import App from './App.vue'
import { createApp } from 'vue'
import PrimeVue from 'primevue/config';
import 'primevue/resources/primevue.min.css';
import 'primevue/resources/themes/lara-dark-blue/theme.css';
import ToastService from 'primevue/toastservice';

const app = createApp(App);

app.use(PrimeVue);
app.use(ToastService);

app.mount('#app')

And here is my App.vue

<template>
    <Toast />

    <button @click="showToast">Show toast!</button>
</template>

<script setup>
    import Toast from 'primevue/toast';
    import { showToast } from './services/toastService';
</script>

and here is my toastService.js:

import { useToast } from "primevue/usetoast";

const showToast = () => {
    const toast = useToast();

    toast.add({ severity: 'info', detail:'Hello' });
}

export { showToast }

>Solution :

Vue composables are primarily supposed to be used directly in setup function, when component instance is created. Some of them can be used in other places but this depends on the implementation of a composable and should be additionally confirmed.

The error suggests that useToast uses inject internally, this restricts the usage of this composable.

For a reusable service, it can be:

import { useToast } from "primevue/usetoast";

export const useToastService = () => {
  const toast = useToast();

  const showToast = () => {
    toast.add({ severity: 'info', detail:'Hello' });
  }

  return { showToast };
};

And used like:

const { showToast } = useToastService();

Nothing in PrimeVue Toast implementation actually requires to use useToast composable, it’s a convenience helper; see this and this. With some risk of refactoring toast service on the next major library update, it could be simplified to using:

import ToastEventBus from 'primevue/toasteventbus';

export const useToastService = () => {
  const showToast = () => {
    ToastEventBus.emit('add', { severity: 'info', detail:'Hello' });
  }

  return { showToast };
};

This way the service could be used with some discretion in any place of the app, e.g. in a router.

#javascript #vue.js #vue-component

Вопрос:

Прежде всего, я не уверен, связано ли это с Vue или просто с вопросом, связанным с JavaScript. Я написал некоторый код, который, наконец, работает, но я не знаю, почему. Может быть, вы сможете просветить меня.

Я создал компонент «диалоговое окно». Это простой (модальный) диалог, который принимает функцию в качестве параметра. Если пользователь нажимает «ОК», вызывается функция типа » Вы действительно хотите удалить этот файл?». Отмените или ОК.

Функция, которую я передаю компоненту, иногда имеет сам параметр. Поэтому я хочу передать уже параметризованную функцию в качестве параметра своему компоненту. Я достигаю этого, обертывая функцию в функцию со стрелкой, которая возвращает параметризованную функцию, которую затем можно вызвать.

Идея этой концепции в чистом JS выглядит так:

 //the function to be finally executed
function say(message) {
  document.getElementById("output").innerHTML = message;
}

//the parameterized function inside of an arrow function (as a variable)
const sayhelloworld = () => say("hello world");

//finally I call the arrow function which 
//returns the parameterized function and calls this one as well
function start() {
  sayhelloworld()(); //this is the core of my question: the double brackets!
}
 

Поэтому мне нужны двойные скобки. Первый () возвращает функцию внутри, а второй () вызывает ее.
И это действительно работает именно так:
https://codepen.io/keztur/pen/powaLJN

Теперь давайте обратимся к vue:

Я открываю свой компонент диалога с помощью шины событий (извините за это) и передаю объект параметра, включая параметр функции. (Я использую Vue 3 — так что за моим объектом EventBus на самом деле стоит библиотека mitt: https://github.com/developit/mitt)

 //component calling the dialog and passing the function parameter 
//(as a part of a parameter object)
EventBus.emit("OpenDialog", {
    header: "Delete file",
    body: "Do you really want to delete that file?",
    function: () => this.Delete(file_id)
});
 

Модальный компонент:

   data() {
    return {
      show: false,
      ModalProps: {
        header: "",
        body: "",
        function: ""
      }
    };
  },

//inside of the modal component this function is called 
//if the user clicks any of the two buttons (cancel or OK)
  methods: {
    clicked(button) {
      if (button === 'ok' amp;amp; typeof this.ModalProps.function === 'function') {
        this.ModalProps.function(); //why does this work ...
       //this.ModalProps.function()(); //...but not this?
 //the second line does call the function but also throws an error afterwards
      }
      this.show = false; //modal is closed
    }
  },
... etc.
 

Поэтому сначала я использовал двойные скобки, как в моем примере JS выше. И функция была вызвана правильно, но при повторном «выполнении», очевидно, возникла ошибка:

 [Vue warn]: Unhandled error during execution of native event handler 
  at <Modal> 
  at <App>
 

Но с тех пор, как я удалил вторую скобку, все работает просто отлично.

Итак, мой вопрос: почему в Vue функция внутри моей функции со стрелкой вызывается сразу, а не просто возвращается по ссылке?

Ответ №1:

Ваш первый пример не работает. Так и должно быть sayhelloworld(); . Откройте консоль (браузер или кодовое имя) при ее запуске. В нем будет сказано:

 TypeError: sayhelloworld() is not a function 
 

Это только выглядит так, как будто это работает, потому что после ошибки больше нечего делать. Попробуйте добавить, например, alert("Done") после sayhelloworld()(); , и вы заметите, что предупреждение никогда не отображается.

Разница в Vue заключается в том, что Vue улавливает и отображает ошибку.

sayhelloworld this.ModalProps.function в вашем примере Vue) — это просто обычные (ссылки на) функции, которые ничего не возвращают. Нет(*) разницы между

 const sayhelloworld = () => say("hello world");
 

и

 const sayhelloworld = function() {
  say("hello world");
}
 

и

 function sayhelloworld() {
  say("hello world");
}
 

Вы бы использовали ()() , если функция возвращает саму функцию, например:

 function sayhelloworld() {
  const innerFunction = function () {
    say("hello world");
  }
  return innerFunction;
}
 

или

 function sayhelloworld() {
  return () => say("hello world");
}
 

или даже

 const sayhelloworld = () => () => say("hello world");
 

Опять же, эти примеры делают то же самое(*).


(*) Они не полностью идентичны, в основном в том, что касается подъема и обработки this внутри функции, но здесь это не имеет значения.

Комментарии:

1. Большое спасибо! Я уже предположил, что проблема как-то связана с js (и моими ограниченными знаниями в этой области). Но я мог бы поклясться, что пытался запустить пример кода только с одной скобкой… вздох

Понравилась статья? Поделить с друзьями:
  • Unhandled error during execution of mounted hook
  • Unexpected error occurred 0x8004060c
  • Ungultige gleitkommaoperation splan как исправить
  • Unexpected error json parse error type mismatch for join on calc info
  • Unfortunately the installation failed error timeout 0x0005