Logical Reuse and Performance Optimization

After completing the routing and login logic, as the project scales, we will find that some logic (such as accessing local data, popping up notifications) appears repeatedly across multiple pages. At the same time, if the task list reaches thousands of items, the page may lag.

In this phase, we will usethe in-depth application of the Composition APIto solve code reuse and performance bottleneck issues.


Logic Reuse: Custom Composables (Hooks)

Composables are the essence of Vue 3; they allow us to extract logic (State + Actions) into independent functions.

useLocalStorage: Data Persistence Logic Extraction

No more manually writing in every Store or componentlocalStorage.getItem。

Example

// src/composables/useLocalStorage.js
import { ref, watch } from 'vue';

export function useLocalStorage(key, defaultValue = null) {
  // 1. Initialize data
  const storedValue = localStorage.getItem(key);
  const data = ref(storedValue ? JSON.parse(storedValue) : defaultValue);

  // 2. Listen for changes and sync automatically
  watch(data, (newValue) => {
    localStorage.setItem(key, JSON.stringify(newValue));
  }, { deep: true });

  return data;
}

useNotification: Common UI Logic Extraction

Implement a simple notification prompt feature.

Example

// src/composables/useNotification.js
import { ref } from 'vue';

export function useNotification() {
  const message = ref('');
  const isVisible = ref(false);

  const notify = (msg, duration = 2000) => {
    message.value = msg;
    isVisible.value = true;
    setTimeout(() => {
      isVisible.value = false;
    }, duration);
  };

  return { message, isVisible, notify };
}

Performance Optimization: Handling Large Data Volumes and High-Frequency Rendering

When your TaskHub grows from managing 10 tasks to managing 1000 tasks, Vue's default "deep reactivity" will bring computational pressure.

shallowRefandmarkRaw

Vue's defaultrefis recursively reactive (i.e., every property inside the object is proxied).

shallowRef: Only listen to.valuethe change of the reference, not the changes of the object's internal properties.

  • Scenario: When you fetch a large read-only list of task history from the backend.

markRaw: Mark an object to make itneverbe converted to reactive.

  • Scenario: Some complex third-party library instances (such as ECharts chart instances, map instances) may cause errors or be extremely performance-intensive if wrapped as reactive.
// 性能优化示例
import { shallowRef, markRaw } from 'vue';

// 假设这是一万条历史归档数据
const archiveTasks = shallowRef([]); 

const loadArchive = (data) => {
  // 仅在赋值时触发一次响应式更新,内部属性修改不触发
  archiveTasks.value = data; 
};

v-onceandv-memo(Directive-level Optimization)

v-once: Static content is rendered only once

If a task no longer changes after rendering (e.g., the task creation time), usev-once。

<span v-once>创建于: {{ task.createdAt }}</span>
  • Principle: Vue will skip subsequent update checks for that node after rendering.

v-memo: On-demand update (Vue 3.2+)

This is the most powerful directive for optimizing long lists. It accepts an array of dependencies; only when the values in the array change, the node and its child nodes will re-render.

<li v-for="task in tasks" :key="task.id" v-memo="[task.isCompleted, task.title]">
  {{ task.title }} - {{ task.isCompleted }}
</li>

When should you optimize?

Solution Problems solved Recommended scenarios
Composables Code duplication, scattered logic Cross-component shared logic (e.g., login checks, theme switching)
shallowRef Memory overhead caused by deep proxying of large objects When list data volume > 1000 and only needs to be replaced wholesale
v-memo Frequent virtual DOM diffing of long lists Complexv-forlists, and only a few properties change per item

Integrating into the Previous Project

You can try toTaskItem.vueapply inv-memo:

<template>
  <li v-memo="[task.id, task.isCompleted]" class="...">
     ...
  </li>
</template>

Now your project is not only logically clear (Composables), but also has strong performance.

Other Extensions