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

Viewed 5000

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?

2 Answers

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.

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>
Related