Vue 3 Hooks Replace Mixins for Cleaner Component Logic Reuse
Vue 2 Mixins made shared logic hard to trace and prone to property name clashes. Custom Hooks give teams an explicit, tree-shakeable, TypeScript-friendly pattern for extracting stateful logic, which scales better across large codebases.
Custom Hooks in Vue 3 are ordinary JavaScript functions, conventionally prefixed with `use`, that bundle reactive state, computed properties, watchers, and lifecycle hooks into reusable units. A `useCounter` Hook, for instance, wraps a `ref`-based count and its increment, decrement, and reset methods, then exposes them for any component to destructure directly in `<script setup>`.
This pattern avoids the naming collisions and opaque data sources that plagued Vue 2 Mixins. Logic is organized by feature rather than by option type, so a single Hook can contain the state, methods, and lifecycle hooks that belong together, keeping components thin and focused on the template.
Best practices stress single-responsibility design, parameterization for configurability, and isolating side effects inside lifecycle hooks rather than in the Hook body. Hooks can also compose and nest, though circular dependencies must be avoided.
The shift from Mixins to Hooks is not just syntactic — it changes how developers trace data flow. With Mixins, a property's origin was often ambiguous; a Hook's explicit import and return make the dependency graph visible.
Vue 3 Hooks borrow the naming convention and mental model from React but ground them in Vue's own reactivity system, which means refs and reactive objects behave differently than React's useState. Developers moving between frameworks need to internalize `.value` access and automatic dependency tracking in `watchEffect`.
The advice to keep side effects out of the Hook body and inside lifecycle hooks is easy to overlook but critical: a Hook that fires a fetch on invocation rather than on mount can cause duplicate requests during server-side rendering or hot module reloading.