Khoá học đang trong giai đoạn preview

Nhập mật khẩu để truy cập nội dung khoá học.

Trung cấp Bài 4/7 · 25 phút đọc

Dữ liệu thật — Kết nối Database

Mục tiêu

Kết nối app với Supabase (database thật). App sẽ lưu dữ liệu vĩnh viễn, không mất khi tải lại trang.

Sau bài này, bạn sẽ:

  • ✅ Tạo được project Supabase và bảng dữ liệu (table)
  • ✅ Kết nối app React với Supabase để đọc/ghi dữ liệu
  • ✅ Hiểu và sử dụng Environment Variables (.env) để bảo mật API key

Nội dung chính

4.1 — Vấn đề: App hiện tại bị “mất trí nhớ”

Ở Course 1, app bạn tạo lưu dữ liệu bằng localStorage — nghĩa là dữ liệu chỉ nằm trong trình duyệt của bạn. Ai dùng máy khác sẽ không thấy. Đổi trình duyệt cũng mất hết.

Hiện tại:  Bạn nhập dữ liệu → Lưu trong trình duyệt → Chỉ bạn thấy
                                                         ↓ Xóa cache = mất hết

Cần làm:   Bạn nhập dữ liệu → Gửi lên Database → Ai cũng thấy
                                                    ↓ Vĩnh viễn không mất

4.2 — Supabase: “Firebase killer” miễn phí

Supabase là một dịch vụ cung cấp Database + Auth + API sẵn, bạn không cần viết Backend phức tạp.

Ẩn dụ: Supabase giống như bạn thuê một kho chứa hàng chuyên nghiệp. Kho có sẵn kệ (bảng dữ liệu), bảo vệ (xác thực), và dịch vụ giao nhận (API). Bạn chỉ cần nói “cần kệ đựng gì” là xong.

Setup Supabase (5 phút):

1. Vào supabase.com → Đăng ký bằng GitHub
2. Bấm "New Project" → Đặt tên → Chọn region gần nhất (Singapore)
3. Đặt database password (LƯU LẠI, sau cần dùng)
4. Chờ 1-2 phút để project khởi tạo
5. Vào Settings → API → Copy 2 giá trị:
   - Project URL (dạng: https://xxxxx.supabase.co)
   - Anon Key (dạng: eyJxxxxxxx — dài ~170 ký tự)
Screenshot: Supabase dashboard — trang Settings → API, đánh dấu Project URL và Anon Key

Mẹo: Anon Key là key công khai, dùng ở phía client (Frontend). Nó an toàn khi kết hợp với Row Level Security (RLS) — sẽ học ở Bài 5. Đừng nhầm với Service Role Key — key đó là “chìa khoá vạn năng”, tuyệt đối không để trong code frontend.

4.3 — Tạo bảng dữ liệu: Khái niệm CS — Table

BẢNG (Table) = Bảng tính Excel trong Database

Bảng "products":
┌────┬──────────────────┬────────┬─────────┐
│ id │ name             │ price  │ image   │
├────┼──────────────────┼────────┼─────────┤
│ 1  │ Trà sữa trân châu│ 35000  │ tra.jpg │
│ 2  │ Cà phê sữa đá   │ 29000  │ cafe.jpg│
│ 3  │ Sinh tố bơ       │ 40000  │ bo.jpg  │
└────┴──────────────────┴────────┴─────────┘
   ↑        ↑               ↑         ↑
 Cột 1    Cột 2           Cột 3     Cột 4
(tự tăng) (text)          (number)  (text)

Tạo bảng trong Supabase — từng bước:

1. Vào Supabase Dashboard → Table Editor (menu bên trái)
2. Bấm "New Table"
3. Đặt tên bảng: products
4. Thêm các cột:
   - id: int8, Primary Key, tự tăng (Is Identity = ON)
   - name: text, không được trống (Is Nullable = OFF)
   - price: int4, không được trống
   - image: text, có thể trống (Is Nullable = ON)
   - created_at: timestamptz, default = now()
5. Bấm "Save"
6. Bấm "Insert Row" để thêm vài dòng dữ liệu test
Screenshot: Supabase Table Editor — tạo bảng products với các cột

Mẹo: Luôn thêm cột created_at với default now(). Sau này bạn sẽ cần biết “dữ liệu nào tạo trước, cái nào tạo sau” để sắp xếp.

4.4 — Yêu cầu AI kết nối

Trong Cursor, dùng Agent mode với prompt chi tiết:

Kết nối app React của tôi với Supabase.

THÔNG TIN SUPABASE:
- URL: https://xxxxx.supabase.co
- Anon Key: eyJxxxxxxx

BƯỚC 1 — CÀI THƯ VIỆN:
Cài @supabase/supabase-js bằng npm

BƯỚC 2 — TẠO FILE KẾT NỐI:
Tạo file src/lib/supabase.js:
- Import createClient từ @supabase/supabase-js
- Đọc URL và Key từ file .env (VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY)
- Export supabase client

BƯỚC 3 — TẠO FILE .ENV:
Tạo file .env ở thư mục gốc:
  VITE_SUPABASE_URL=https://xxxxx.supabase.co
  VITE_SUPABASE_ANON_KEY=eyJxxxxxxx

BƯỚC 4 — HIỂN THỊ DỮ LIỆU:
Trong trang Home, gọi dữ liệu từ bảng "products":
- Dùng useEffect để fetch data khi trang load
- Hiển thị dạng grid ProductCard (3 cột desktop, 1 cột mobile)
- Hiện loading spinner khi đang tải
- Hiện thông báo "Chưa có sản phẩm" nếu bảng trống

BƯỚC 5 — FORM THÊM SẢN PHẨM:
Thêm form để thêm sản phẩm mới vào database:
- Input: tên sản phẩm, giá, URL ảnh
- Nút "Thêm sản phẩm"
- Sau khi thêm → tự động refresh danh sách
- Validate: tên không được trống, giá phải > 0

LƯU Ý QUAN TRỌNG:
- URL và Key PHẢI để trong file .env, KHÔNG hard-code
- Thêm .env vào file .gitignore

Prompt nâng cao (thêm chức năng xóa và sửa):

Dựa trên code vừa tạo, thêm chức năng cho mỗi ProductCard:

1. Nút "Xóa" (icon thùng rác):
   - Hiện popup xác nhận "Bạn chắc chắn muốn xóa?"
   - Xóa xong → refresh danh sách

2. Nút "Sửa" (icon bút chì):
   - Click → ProductCard chuyển thành form sửa (inline edit)
   - Nút "Lưu" và "Hủy"
   - Lưu xong → quay lại hiển thị bình thường

Tham chiếu @src/lib/supabase.js cho kết nối database.

Khái niệm CS lồng ghép: Environment Variables (.env) File .env là nơi lưu thông tin nhạy cảm (API key, mật khẩu database). Giống như két sắt trong nhà — bạn không treo chìa khoá ngoài cửa.

Lỗi thường gặp

Vấn đề: “Dữ liệu không hiển thị” — app chạy nhưng không thấy sản phẩm nào → Kiểm tra 3 thứ theo thứ tự: (1) File .env có đúng URL và Key không? (2) Đã thêm dữ liệu test vào bảng Supabase chưa? (3) Mở Console trong trình duyệt (F12 → Console) xem có lỗi đỏ không. Lỗi phổ biến nhất: copy thiếu ký tự trong Anon Key.

Vấn đề: “RLS block” — thêm dữ liệu thành công nhưng không đọc được → Supabase mặc định bật Row Level Security. Nếu chưa tạo policy, mọi truy vấn sẽ trả về rỗng. Vào Supabase → Authentication → Policies → tạo policy “Enable read access for all users” cho bảng products. Ở Bài 5 sẽ học RLS chi tiết hơn.

Vấn đề: “Lỗi ‘supabaseUrl is required’” khi chạy app → File .env chưa được đọc. Kiểm tra: (1) File .env nằm ở thư mục gốc (cùng cấp với package.json). (2) Biến phải bắt đầu bằng VITE_ (ví dụ: VITE_SUPABASE_URL). (3) Sau khi tạo/sửa .env, phải tắt server (Ctrl + C) rồi chạy lại npm run dev.

Vấn đề: “Thêm sản phẩm thành công nhưng danh sách không cập nhật” → Sau khi insert dữ liệu mới, cần gọi lại hàm fetch danh sách. Nói AI: “Sau khi thêm sản phẩm thành công, gọi lại hàm fetchProducts() để refresh danh sách”.

Mẹo: Khi debug lỗi Supabase, mở tab Network trong DevTools (F12 → Network). Tìm request đến supabase.co và xem response. Nếu response trả về [] (mảng rỗng) thì thường là lỗi RLS. Nếu trả về lỗi 401/403 thì sai API key.

Bài tập thực hành

Nhiệm vụ:

Bước 1 (5 phút): Tạo tài khoản Supabase, tạo project mới

  • Tiêu chí: có Project URL và Anon Key

Bước 2 (5 phút): Tạo bảng tasks gồm: id, title (text), completed (boolean, default false), created_at (timestamptz, default now())

  • Tiêu chí: bảng có ít nhất 3 dòng dữ liệu test
  • Gợi ý nếu bị stuck: làm theo hướng dẫn từng bước ở phần 4.3

Bước 3 (10 phút): Dùng Cursor Agent mode, yêu cầu AI kết nối app với Supabase

  • Tiêu chí: file .env có URL và Key, file supabase.js kết nối thành công

Bước 4 (10 phút): Tạo app To-do list đọc/ghi dữ liệu từ Supabase

  • Tiêu chí: thêm task mới → tải lại trang → task vẫn còn
  • Gợi ý nếu bị stuck: nếu dữ liệu không hiện, kiểm tra Console (F12) và đọc phần “Lỗi thường gặp” bên trên

Thời gian: 30 phút Deliverable: App To-do chạy trên localhost, thêm task → tải lại trang → task vẫn còn

Tổng kết bài 4

Bạn đã học đượcChi tiết
Database là gìKho dữ liệu vĩnh viễn, ai cũng truy cập được
SupabaseDịch vụ Database miễn phí, dễ dùng
Table, Row, ColumnCấu trúc dữ liệu giống bảng Excel
.envFile lưu thông tin nhạy cảm, không share
CRUDCreate (thêm), Read (đọc), Update (sửa), Delete (xóa) dữ liệu

Kiểm tra kiến thức

1. Tại sao cần kết nối database thay vì dùng localStorage?

2. File .env dùng để làm gì?

3. Trong Supabase, Table (bảng) có cấu trúc giống gì?

4. Khi tạo biến môi trường cho project Vite, tên biến phải bắt đầu bằng gì?

5. Sau khi tạo/sửa file .env, cần làm gì để app nhận được giá trị mới?

Tham gia Bình Dân AI

Hoàn toàn miễn phí. Bạn sẽ nhận được:

Vào group Zalo ngay

Miễn phí mãi mãi. Không spam. Rời group bất cứ lúc nào.