跪拜 Guibai
← Back to the summary

Vue 3 Hooks Replace Mixins for Cleaner Component Logic Reuse

Vue3 Hooks Practical Usage Analysis

Foreword

In Vue.js application development, as business logic becomes more complex, components often need to handle repetitive logic (such as data fetching, form validation, event listening, global state management). The traditional approach is to write this logic directly inside the component, leading to code redundancy, difficulty in maintenance, and violation of the "separation of concerns" principle. The Composition API introduced in Vue 3 provides a more elegant solution for logic reuse: Vue Hooks, which can separate logic such as state, methods, and lifecycle hooks, making component code clearer and easier to maintain.

1. Core Concepts and Functions

1.1 What are Vue Hooks

Hooks are not a concept unique to Vue; they originally came from a new functional programming mindset introduced after React 16. In React, Hooks provide a series of functions starting with use, allowing developers to complete almost all component development work in functional components, including lifecycle, state management, and logic reuse.

In Vue 3, Hooks combine with Vue's reactivity system to become a powerful mechanism for encapsulating and reusing state logic. They allow developers to split Vue component logic into multiple independent, reusable functions, which are called Hooks. Each Hook encapsulates a piece of code with state logic that can be shared and reused across multiple components.

1.2 Core Value

2. Basic Hooks Classification

Vue 3 has a built-in series of basic Hooks for implementing core functionalities like reactivity and lifecycle management.

2.1 Reactive State

Used to create and manage reactive data, as shown in the table below.

Hook Function
ref Creates reactive data for primitive types (or objects) (accessed via .value)
reactive Creates reactive data for object types (access properties directly)
toRef Converts a property of a reactive object into a ref (maintains reactive connection)
toRefs Converts all properties of a reactive object into ref objects (for destructuring)
watch Watches reactive data changes (explicitly specifies the source)
watchEffect Automatically tracks reactive dependencies and executes when dependencies change (no need to explicitly specify the source)
<script setup lang="ts">

import { ref, reactive,  toRef, toRefs  } from 'vue'

const count = ref(0)

const user = reactive({ name: 'Zhang San', age: 20 })

const nameRef = toRef(user, 'name')

const { name, age } = toRefs(user) // Still reactive after destructuring
</script>

2.2 Computed and Watchers

Hook Function
computed Creates a computed property (depends on reactive data, automatically caches results)
watch Watches reactive data changes (explicitly specifies the source)
watchEffect Automatically tracks reactive dependencies and executes when dependencies change (no need to explicitly specify the source)
<script setup lang="ts">

import { ref, computed, watchEffect  } from 'vue'
  
const count = ref(0)

const doubleCount = computed(() => count.value * 2)

watchEffect(() => { 
  console.log(`Current count value: ${count.value}`)
})
</script>

2.3 Lifecycle Hooks

In the Composition API, they exist as functions and must be used within setup or <script setup>.

Hook Corresponding Vue 2 Lifecycle Function
onMounted mounted Executes after the component is mounted
onUpdated updated Executes after the component is updated
onUnmounted unmounted Executes after the component is unmounted
onBeforeMount beforeMount Executes before the component is mounted
onBeforeUpdate beforeUpdate Executes before the component is updated
onBeforeUnmount beforeDestroy Executes before the component is unmounted
onErrorCaptured Executes when catching an error from a child component
onActivated Executes when a cached component (KeepAlive) is activated
onDeactivated Executes when a cached component is deactivated
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  console.log('Component mounted')
  // Example: Initialize timers, event listeners
})

onUnmounted(() => {
  console.log('Component unmounted')
  // Example: Clear timers, event listeners
})
</script>

2.4 Other Basic Hooks

Hook Function
shallowRef Creates "shallow reactive" data (only top-level is reactive)
shallowReactive Creates "shallow reactive" objects (only top-level properties are reactive)
readonly Creates read-only reactive data (modifications are forbidden)
<script setup lang="ts">
import { reactive, toRef, toRefs, shallowRef, readonly } from 'vue' 
  
const user = reactive({ name: 'Zhang San', age: 20 })

const nameRef = toRef(user, 'name')

const { name, age } = toRefs(user) // Still reactive after destructuring

const obj = shallowRef({ a: 1 }) // Modifying obj.value.a will not trigger an update; reassigning obj.value will

const readOnlyUser = readonly(user) // Modifying readOnlyUser.name will throw an error
</script>

3. Basic Usage of Hooks

In Vue 3, custom Hook functions are an important means of improving code reusability and organization. State management, business logic, etc., can be encapsulated in custom Hooks. These functions are created using the Composition API, can contain any combination logic, and can be shared among multiple components. By encapsulating reusable logic code, developers can build and maintain large applications more efficiently.

3.1 Creating a Hook Function

Generally, we create a hooks folder under the src folder to uniformly store the hook code used in the program. Let's write a simple hook with an example, as shown below.

A custom Hook is a regular JavaScript function, usually named with a use prefix. It can use functions provided by the Composition API to manage state and side effects. After creating the hooks folder under the src folder, create a useCounter.js file inside it with the following code:

import { ref } from 'vue'

// Define a Hook named useCounter
export function useCounter(initVal = 0) {
  // Define a reactive state
  const count = ref(initVal);

  // Define a method to increase the state
  const increment = () => {
    count.value++;
  };
  // Define a method to decrease the state
  const decrement = () => {
    count.value--;
  };
  // Define a method to reset the state
  const reset = () => {
    count.value = initVal;
  };

  // Return state and methods for external use
  return { count, increment, decrement, reset };
}

3.2 Using a Custom Hook

In the example above, we defined a Hook named useCounter, which encapsulates a reactive state and three methods for operating on the state. Using custom Hooks is very simple: just import and call them in the component's <script setup>, destructure the required properties and methods, and they can be used directly in the template:

<script setup>
import { useCounter } from '@/hooks/useCounter'

// Destructure and use directly, no need to redefine variables
const { count, increment, reset } = useCounter(10)
</script>

<template>
  <div>Current Count: {{ count }}</div>
  <button @click="increment">+</button>
  <button @click="reset">Reset</button>
</template>

In the example above, the useCounter Hook is called in the component's setup function to get the state and methods, which are then exposed to the template for use. This way, we have successfully achieved state encapsulation and reuse.

4. Best Practices for Hooks

4.1 Design Principles

Custom Hooks are a pattern for handling component logic, allowing us to reuse state logic without copying and pasting code between components. Custom hooks are simple JavaScript functions, but the following should be observed when using them:

5. Summary

As a new mechanism for encapsulating and reusing state logic introduced in Vue 3, Hooks provide us with a more flexible and efficient way to organize and reuse code. By learning and mastering the use of Hooks, we can better cope with the demands of complex Vue project development, improving code maintainability and readability. At the same time, Hooks also provide us with a new functional programming mindset, helping us better understand and grasp the essence of Vue development.