Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue Composition API: Is there a better way in calling `emit` inside consumable file?

What is the correct way (or a better way) to access emit in the separated logic file?

This is what I did currently that works:

foo.js

export default (emit) => {
    const foo = () => { emit('bar') };
    return { foo };
}

Then on the consuming component:

import { defineComponent } from '@vue/composition-api';
import foo from './foo';

export default defineComponent({
  setup(props, { emit }) {
    const { foo } = foo(emit);
    return { foo };
  }
});

But I wonder if there is a more appropriate way on doing this? Or is it a bad practice to call emit inside a consumable file?

like image 636
rmondesilva Avatar asked Jan 25 '23 15:01

rmondesilva


1 Answers

You probably have found the solution, but in case you would try similar way (as originally asked in question), there's this option called getCurrentInstance that has an emitter (the Vue 2 plugin for Composition API has one too).

import { getCurrentInstance } from 'vue';

export default () => {
  const { emit } = getCurrentInstance();

  const foo = () => {
    emit('bar');
  };

  return { foo };
}

But bear in mind that this will only work for calling functions/components that have the SetupContext.

Edit

The above solution will work for Vue 3, yet with earlier version of Vue + the Composition API plugin, there is but a slight difference: As with the rest of the Instance Properties, you'll have to prefix it with $ to become $emit. (The following example now assumes Typescript as the target language, as mentioned on the comment).

import { getCurrentInstance } from '@vue/composition-api';

export default () => {
  // Ugly workaround, since the plugin did not have the `ComponentInstance` type exported. 
  // You could use `any` here, but that would defeat the purpose of having type-safety, won't it?
  // And we're marking it as `NonNullable` as the consuming components 
  // will most likely be (unless desired otherwise).
  const { $emit, ...context } = getCurrentInstance() as NonNullable<ReturnType<typeof getCurrentInstance>>;

  const foo = () => {
    $emit.call(context, 'bar');
  };

  return { foo };
}

For Vue 3's Composition API, however, they do have this ComponentInternalInstance interface exported.

P.S. It's probably best to stick to the old-school way of assigning the instance to a variable and do context.$emit or vm.$emit rather than having to explicitly specify a context for everything. I initially came up with this idea without realizing that those Instance Properties are probably meant for internal uses, which is not exactly the case with the next Composition API.

like image 86
Yom T. Avatar answered Jan 30 '23 10:01

Yom T.