vue.jsvuejs3vue-composition-apivue-mixin

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

  • 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.