Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

[Vue warn]: inject() can only be used inside setup() or functional components

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

[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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading