'Vue 3 Composition API - How to specify a prop in setup()

I wrote a "loading state" mixin for Vue 2:

export default {
  props: {
    loading: {
      type: Boolean,
      default: false
    },
  },
  data () {
    return {
      innerLoading: false,
    }
  },
  mounted () {
    this.innerLoading = !!this.loading
  },
  methods: {
    startLoading () {
      this.$emit('update:loading', this.innerLoading = true)
    },
    stopLoading () {
      this.$emit('update:loading', this.innerLoading = false)
    },
  },
  computed: {
    isLoading () {
      return !!this.innerLoading
    },
    isNotLoading () {
      return !this.innerLoading
    },
  },
  watch: {
    loading (loading) {
      this.innerLoading = !!loading
    },
  }
}

I use this mixin for other components to hold the loading state. For example for forms, buttons, tables etc.

Now, Im trying to rewrite this mixin to composition API style for Vue 3. Ideally, I would like to use my loading composable like this:

// components/Table.vue

import 'useLoading' from 'src/composables/loading'

export default defineComponent({
  setup () {
    const { startLoading, stopLoading, innerLoading } = useLoading()

    // ...
    
    return { startLoading, stopLoading, innerLoading, ... }
  }
})

My question:

// How can I define the loading prop inside the setup() function?
props: {
  loading: {
    type: Boolean,
    default: false
  },
},

Of course I can define my component like this:

import 'useLoading' from 'src/composables/loading'

export default defineComponent({
  props: {
    loading: {
      type: Boolean,
      default: false
    },
  },
  setup () {
    const { startLoading, stopLoading, innerLoading } = useLoading();
  }
})

But imagine, I have 20 components using this mixin/composable. So I want to define that loading prop only ONCE (like I did in mixin).

Is there a way how to do it with composition API?



Solution 1:[1]

you may be able to do something like this

import {withProps, useLoading} from "src/composables/loading";

export default defineComponent({
  props: {
    ...withProps()
  },
  setup () {
    const { startLoading, stopLoading, innerLoading } = useLoading();
  }
})

where withProps is a function that would have your definitions

export const withProps = () => ({
  loading: {
    type: Boolean,
    default: false
  },
})

of course it doesn't need to be a function, but in some cases it may be helpful and preemptively making it a function can make api consistent.

Solution 2:[2]

Define an Object called loadingProps in separate file called makeLoadingProps:

export const loadingProps = {
    loading: {
        type: Boolean,
        default: false
    }
}

then import it inside your component defined using the script setup syntax:

<script setup lang="ts">

import {defineProps} from 'vue'
import { loadingProps } from 'src/composables/makeLoadingProps';

const props = defineProps({
               ...loadingProps,
                //other props
             })

const { startLoading, stopLoading, innerLoading } = useLoading(props)

</script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2