Constantin Druccdruc

Hey, I'm Constantin Druc!

I'm a web developer sharing everything I know about building web applications.

Function props in vue3 - when to use them

In a recent youtube video, I passed a function prop instead of attaching an event listener. I'll explain why but first, let's look at a simplified version of that component.

<script setup>
import {ref} from "vue";
import Alert from "./Alert.vue";

const showAlert = ref(true);
</script>

<template>
  <Alert
    v-if="showAlert"
    :on-dismiss="() => showAlert = false"
  >
    This is a dismissible alert. Click the button to hide it.
  </Alert>
</template>

In the example above:

  • showAlert controls wether or not the alert is visible.
  • onDismiss is a function prop that sets showAlert to false, which then hides the alert.

The question is, why use a function prop and not a regular event listener?

The answer lies in the Alert component itself. Look at the code below. Can you guess why I chose to use a prop and not emit a "dismiss" event?

<script setup>
const props = defineProps({
  onDismiss: Function
});
</script>

<template>
  <div>
    <slot/>
    <button
      v-if="onDismiss"
      @click="onDismiss()"
    >
      Dismiss
    </button>
  </div>
</template>

If your answer had to do something with the v-if="onDismiss", you are correct.

In Vue3, there is no way to check for attached event listeners.

We only display the dismiss button if the user passes in an onDismiss prop; otherwise, we consider the alert a "non-dismissible" one.

The alternative would be to emit a "dismiss" event and also have something like a "dismissible" boolean prop. That is not only lengthier because you now have to add two attributes but also more error-prone because you migh forget to pass one or the other.

<script setup>
import {ref} from "vue";
import Alert from "./Alert.vue";

const showAlert = ref(true);
</script>

<template>
  <Alert
    v-if="showAlert"
    @dismiss="() => showAlert = false"
  >
    Should be dismissible but I forgot about the "dismissible" prop, so there's no Dismiss button anymore 😢.
  </Alert>
</template>

Generally, it's best to stay close to the guidelines of the language or the framework you're using, but sometimes those guidelines can be broken - and this is one of those times. 🤷‍♂️

Tags: