0
0
Lập trình
Admin Team
Admin Teamtechmely

Quản lý State Hydration và Persisted State trong Nuxt với Pinia

Đăng vào 5 ngày trước

• 5 phút đọc

Quản lý State Hydration và Persisted State trong Nuxt với Pinia

Khi làm việc với Nuxt (hoặc bất kỳ framework SSR nào), một trong những phần khó khăn nhất là xử lý state hydration — đảm bảo rằng trạng thái mà bạn tạo ra trên máy chủ khớp với những gì chạy trên máy khách. Nếu những trạng thái này khác nhau, bạn sẽ thường thấy cảnh báo về hydration, giao diện nhấp nháy, hoặc thậm chí là sự tương tác bị hỏng.

Trong bài viết này, chúng ta sẽ khám phá:

  • Khái niệm về state hydration trong SSR
  • Những cạm bẫy phổ biến mà lập trình viên gặp phải
  • Cách duy trì trạng thái giữa SSR và điều hướng phía máy khách với PiniaTypeScript
  • Những sửa chữa và mẫu thực tế bạn có thể áp dụng

🤔 State Hydration và những cạm bẫy phổ biến

Khi một trang được render trên máy chủ, Nuxt gửi HTML đến trình duyệt. Sau đó, Vue sẽ chiếm quyền kiểm soát và hydrate phần markup đó bằng JavaScript phía máy khách, gắn bó với khả năng phản hồi và các trình lắng nghe sự kiện. Nếu trạng thái phía máy khách không khớp với những gì đã được render trên máy chủ, Vue sẽ thông báo lỗi:

Copy
[Vue warn]: Hydration completed but contains mismatches.

Điều này thường xảy ra với trạng thái động, đặc biệt là khi sử dụng các store.

Những cạm bẫy phổ biến

a) Sử dụng API chỉ có trên trình duyệt trong ngữ cảnh máy chủ

javascript Copy
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    theme: localStorage.getItem('theme') || 'light', // ❌ sẽ bị lỗi trong SSR
  }),
})

Trên máy chủ, localStorage không tồn tại, vì vậy Nuxt sẽ gặp lỗi hoặc render một giá trị mặc định. Sau đó, trên máy khách, giá trị thay đổi → không khớp trong hydration.

b) Dữ liệu không xác định

Bất cứ thứ gì thay đổi giữa máy chủ và máy khách — ví dụ: Date.now(), Math.random() — sẽ gây ra không khớp nếu được sử dụng trực tiếp trong trạng thái.

c) Quên duy trì trạng thái giữa các lần điều hướng

Nếu store của bạn được thiết lập lại sau mỗi lần điều hướng, bạn sẽ mất trạng thái (như sở thích người dùng, mã xác thực, hoặc dữ liệu giỏ hàng).

🟢 Sử dụng Pinia với Nuxt

Nuxt hỗ trợ Pinia một cách hoàn hảo thông qua mô-đun @pinia/nuxt. Điều này giúp tuần tự hóa và giải tuần tự hóa trạng thái store giữa máy chủ và máy khách.

Cài đặt:

Copy
npm install pinia @pinia/nuxt

Thêm vào nuxt.config.ts:

javascript Copy
export default defineNuxtConfig({
  modules: [
    '@pinia/nuxt',
  ],
  pinia: {
    autoImports: ['defineStore', 'storeToRefs'],
  },
})

4. Duy trì trạng thái với Plugins

Pinia không tự động duy trì trạng thái. Nhưng bạn có thể thêm một plugin:

javascript Copy
// plugins/persistedState.client.ts
import { defineNuxtPlugin } from '#app'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

export default defineNuxtPlugin(({ $pinia }) => {
  $pinia.use(piniaPluginPersistedstate)
})

Sau đó trong store của bạn:

javascript Copy
export const useUserStore = defineStore('user', {
  state: () => ({
    theme: 'light' as 'light' | 'dark',
  }),
  persist: true, // 👈 được lưu trữ trong localStorage theo mặc định
})

Bây giờ trạng thái của bạn sẽ sống sót qua các lần tải lại trang và điều hướng phía máy khách.


5. Tránh không khớp SSR với TypeScript

Khi định nghĩa trạng thái với TypeScript, hãy luôn cung cấp các giá trị khởi tạo an toàn cho SSR:

javascript Copy
export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [] as { id: string; qty: number }[],
    initialized: false,
  }),
  actions: {
    init() {
      if (process.client) {
        this.items = JSON.parse(localStorage.getItem('cart') || '[]')
      }
      this.initialized = true
    },
  },
})

Những điều cần nhớ:

  • Luôn kiểm tra process.client trước khi sử dụng API trên trình duyệt.
  • Khởi tạo trạng thái với các giá trị mặc định an toàn cho SSR.
  • Chỉ hydrate dữ liệu bổ sung sau khi máy khách đã chiếm quyền kiểm soát.

✅ Những thực tiễn tốt nhất

  1. Sử dụng giá trị mặc định an toàn cho SSR cho tất cả trạng thái store.
  2. Bọc logic chỉ dành cho khách hàng trong các khối if (process.client).
  3. Duy trì trạng thái quan trọng (xác thực, sở thích, giỏ hàng) với pinia-plugin-persistedstate.
  4. Xem xét việc lấy dữ liệu từ máy chủ cho trạng thái khởi tạo, sau đó hydrate các dữ liệu chỉ dành cho khách hàng sau.
  5. Sử dụng TypeScript để định kiểu nghiêm ngặt cho các store của bạn, tránh các giá trị undefined hoặc any không mong muốn gây ra sự không khớp.

📖 Tìm hiểu thêm

Nếu bạn muốn tìm hiểu thêm về Vue, Nuxt, JavaScript hoặc các công nghệ hữu ích khác, hãy khám phá VueSchool bằng cách nhấp vào liên kết này hoặc hình ảnh bên dưới:

Nó bao gồm các khái niệm quan trọng nhất trong việc xây dựng các ứng dụng Vue hoặc Nuxt hiện đại có thể giúp bạn trong công việc hàng ngày hoặc các dự án bên lề của bạn 😉

🧪 Kỹ năng nâng cao

Một chứng chỉ nâng cao kỹ năng của bạn, xây dựng uy tín và mở ra cơ hội mới. Dù bạn đang tiến xa trong sự nghiệp hay chuyển hướng, đó là một bước thông minh hướng tới thành công.

Khám phá Certificates.dev bằng cách nhấp vào liên kết này hoặc hình ảnh bên dưới:

Đầu tư vào bản thân — hãy được chứng nhận trong Vue.js, JavaScript, Nuxt, Angular, React và nhiều hơn nữa!

✅ Tóm tắt

State hydration là một trong những cạm bẫy tinh vi nhất của SSR trong Nuxt. Bằng cách kết hợp Pinia, tích hợp SSR của Nuxt, và an toàn kiểu của TypeScript, bạn có thể tránh những không khớp trong hydration và đảm bảo ứng dụng của bạn hoạt động nhất quán giữa máy chủ và máy khách.

Lần tới khi bạn thấy [Vue warn]: Hydration completed but contains mismatches, hãy kiểm tra thiết lập khởi tạo và duy trì store của bạn trước tiên — rất có thể, cách khắc phục nằm ở đó.

Chúc bạn làm việc hiệu quả và vui vẻ với lập trình như thường lệ 🖥️

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào