--- title: Use Composables Instead of Mixins for Logic Reuse impact: HIGH impactDescription: Mixins cause naming conflicts, unclear data origins, and inflexible logic - composables solve all these problems type: best-practice tags: [vue3, composition-api, composables, mixins, refactoring, code-reuse] --- # Use Composables Instead of Mixins for Logic Reuse **Impact: HIGH** - Mixins, the primary logic reuse mechanism in Options API, have fundamental flaws that make code hard to maintain. Composables (Composition API functions) solve all mixin drawbacks: unclear property origins, naming conflicts, and inability to parameterize. The ability to create clean, reusable logic through composables is the primary advantage of the Composition API. ## Task Checklist - [ ] Migrate existing mixins to composables when refactoring - [ ] Never create new mixins - use composables instead - [ ] Use explicit imports to make data origins clear - [ ] Parameterize composables to make them flexible - [ ] Prefix composables with "use" (useAuth, useFetch, useForm) **Problems with Mixins:** ```javascript // userMixin.js export const userMixin = { data() { return { user: null, loading: false // Conflict waiting to happen! } }, methods: { fetchUser() { /* ... */ } } } // authMixin.js export const authMixin = { data() { return { token: null, loading: false // NAME CONFLICT with userMixin! } }, methods: { login() { /* ... */ } } } // Component using mixins - PROBLEMATIC export default { mixins: [userMixin, authMixin], mounted() { // PROBLEM 1: Where does 'user' come from? Have to check mixins console.log(this.user) // PROBLEM 2: Which 'loading'? Last mixin wins, silently! console.log(this.loading) // Is this user loading or auth loading? // PROBLEM 3: Can't customize behavior per-component this.fetchUser() // Always fetches the same way } } ``` **Composables Solution:** ```javascript // composables/useUser.js import { ref } from 'vue' export function useUser(userId) { // Can accept parameters! const user = ref(null) const loading = ref(false) const error = ref(null) async function fetchUser() { loading.value = true try { user.value = await api.getUser(userId) } catch (e) { error.value = e } finally { loading.value = false } } return { user, loading, error, fetchUser } } // composables/useAuth.js import { ref } from 'vue' export function useAuth() { const token = ref(null) const loading = ref(false) // No conflict - it's scoped! async function login(credentials) { /* ... */ } function logout() { /* ... */ } return { token, loading, login, logout } } // Component using composables - CLEAR AND FLEXIBLE ``` ## Migrating from Mixins ```javascript // BEFORE: Mixin with options export const formMixin = { data() { return { errors: {}, submitting: false } }, methods: { validate() { /* ... */ }, submit() { /* ... */ } } } // AFTER: Composable with flexibility export function useForm(initialValues, validationSchema) { const values = ref({ ...initialValues }) const errors = ref({}) const submitting = ref(false) const touched = ref({}) function validate() { errors.value = validationSchema.validate(values.value) return Object.keys(errors.value).length === 0 } async function submit(onSubmit) { if (!validate()) return submitting.value = true try { await onSubmit(values.value) } finally { submitting.value = false } } function reset() { values.value = { ...initialValues } errors.value = {} touched.value = {} } return { values, errors, submitting, touched, validate, submit, reset } } // Usage - now parameterizable and explicit const loginForm = useForm( { email: '', password: '' }, loginValidationSchema ) const registerForm = useForm( { email: '', password: '', name: '' }, registerValidationSchema ) ``` ## Composition Over Mixins Benefits | Aspect | Mixins | Composables | |--------|--------|-------------| | Property origin | Unclear | Explicit import | | Naming conflicts | Silent overwrites | Explicit rename | | Parameters | Not possible | Fully supported | | Type inference | Poor | Excellent | | Reuse instances | One per component | Multiple allowed | | Tree-shaking | Not possible | Fully supported | ## Reference - [Composition API FAQ - Better Logic Reuse](https://vuejs.org/guide/extras/composition-api-faq.html#better-logic-reuse) - [Composables](https://vuejs.org/guide/reusability/composables.html) - [VueUse - Collection of Composables](https://vueuse.org/)