6

I have a vue composable that needs to fire an event. I naively set it up as follows:

*// composable.js*
import { defineEmits } from "vue";

export default function useComposable() {
  // Vars
  let buffer = [];
  let lastKeyTime = Date.now();
  const emit = defineEmits(["updateState"]);

document.addEventListener("keydown", (e) => {
    // code
    emit("updateState", data);
   }

// *App.vue*
<template>
<uses-composables
    v-show="wirtleState.newGame"
    @updateState="initVars"
  ></uses-composables>
</template>
<script setup>
const initVars = (data) => {
//code here

}

// usesComposable.vue
<template>
  <button @click="resetBoard" class="reset-button">Play Again</button>
</template>

<script setup>
import { defineEmits } from "vue";
import useEasterEgg from "@/components/modules/wirdle_helpers/useEasterEgg.js";


useEasterEgg();
</script>

The error I get is "Uncaught TypeError: emit is not a function useEasterEgg.js:30:11

So obviously you can not use defineEmits in a .js file. I dont see anywhere in Vue docs where they specifically use this scenario. I dont see any other way to do this but using $emits but that is invoked in a template which my composable does not have. Any enlightenment much appreciated.

Alan
  • 1,067
  • 1
  • 23
  • 37

3 Answers3

4

You can emit events from a composable, but it will need to know where the events should be fired from using context which can be accessed from the second prop passed to the setup function: https://vuejs.org/api/composition-api-setup.html#setup-context

Composable:

    export default function useComposable(context) {
      context.emit("some-event")
    }

Component script:

    <script>
    import useComposable from "./useComposable"
    export default {
       emits: ["some-event"],
       setup(props, context) {
           useComposable(context)   
       }
    }
    </script>
Luigi Minardi
  • 343
  • 4
  • 13
Hugo
  • 541
  • 7
  • 21
4

To use it in a script setup, the best way I found was to declare the defineEmit first, and assigning it to a const, and pass it as a param to your composable :

const emit = defineEmit(['example']
useMyComposable(emit);

function useMyComposable(emit){
   emit('example')
}
1

You can't access emit this way, as the doc says : defineProps and defineEmits are compiler macros only usable inside script setup. https://vuejs.org/api/sfc-script-setup.html

I'm not entirely sure of what you are trying to achieve but you can use vue-use composable library to listen to key strokes https://vueuse.org/core/onkeystroke/

Lx4

Lx4
  • 46
  • 3
  • The updateState event reinitializes the app state. I need this done under certain conditions so I put it in eventListener that listens for certain key combo and added it to the composable. Then when needed fire the event => call initVars from parent component. to keep things. DRY... – Alan May 26 '22 at 17:19