Giới thiệu
Trong thời đại công nghệ hiện nay, việc quản lý công việc cá nhân trở nên quan trọng hơn bao giờ hết. Một ứng dụng todo đơn giản nhưng hiệu quả có thể giúp chúng ta sắp xếp thời gian, theo dõi tiến độ và tăng năng suất làm việc. Supabase - một nền tảng Backend-as-a-Service (BaaS) mã nguồn mở - kết hợp với React - thư viện JavaScript phổ biến nhất hiện nay - tạo nên một cặp đôi hoàn hảo để xây dựng ứng dụng todo nhanh chóng và mạnh mẽ.
Bài viết này sẽ hướng dẫn bạn từng bước xây dựng một ứng dụng todo hoàn chỉnh, từ thiết lập cơ sở dữ liệu đến triển khai giao diện người dùng. Dù bạn là người mới bắt đầu hay đã có kinh nghiệm, bạn sẽ tìm thấy những kiến thức hữu ích để phát triển ứng dụng của riêng mình.
Chuẩn bị môi trường phát triển
Cài đặt các công cụ cần thiết
Trước khi bắt đầu, chúng ta cần chuẩn bị một số công cụ cơ bản:
- Node.js và npm: Đây là runtime JavaScript và trình quản lý gói cần thiết để chạy ứng dụng React. Bạn có thể tải về từ trang chủ Node.js. - Supabase: Đăng ký tài khoản miễn phí tại supabase.com để sử dụng dịch vụ database và authentication. - Trình soạn thảo code: VS Code là lựa chọn phổ biến với nhiều extensions hữu ích.
Khởi tạo dự án React
Mở terminal và chạy lệnh:
npx create-react-app todo-app
cd todo-app
Lệnh này sẽ tạo một dự án React mới với cấu trúc thư mục cơ bản. Tiếp theo, chúng ta cần cài đặt Supabase client:
npm install @supabase/supabase-js
Thiết lập Supabase
Tạo database và schema
Sau khi đăng nhập vào Supabase, tạo một project mới. Trong phần Database, chúng ta sẽ tạo một bảng todos với các cột:
- id: SERIAL PRIMARY KEY
- title: TEXT
- description: TEXT
- is_completed: BOOLEAN mặc định false
- created_at: TIMESTAMP mặc định NOW()
Schema này cho phép chúng ta lưu trữ thông tin công việc với trạng thái hoàn thành và thời gian tạo.
Cấu hình authentication
Supabase cung cấp sẵn hệ thống authentication. Chúng ta có thể cho phép người dùng đăng ký bằng email và password. Trong bảng auth.users, Supabase tự động tạo các cột cần thiết.
Xây dựng components React
Component TodoList
Đây là component chính hiển thị danh sách các công việc. Chúng ta sẽ sử dụng hook useState để quản lý trạng thái local và useEffect để fetch dữ liệu từ Supabase.
import { useState, useEffect } from 'react';
import { supabase } from './supabaseClient';
function TodoList() {
const [todos, setTodos] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchTodos();
}, []);
async function fetchTodos() {
const { data, error } = await supabase
.from('todos')
.select('*')
.order('created_at', { ascending: false });
if (error) console.error(error);
else setTodos(data);
setLoading(false);
}
return (
<div>
{loading ? (
<p>Đang tải...</p>
) : (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.is_completed}
onChange={() => toggleTodo(todo.id, !todo.is_completed)}
/>
<span style={{ textDecoration: todo.is_completed ? 'line-through' : 'none' }}>
{todo.title}
</span>
</li>
))}
</ul>
)}
</div>
);
}
Component TodoForm
Component này cho phép người dùng thêm công việc mới:
import { useState } from 'react';
import { supabase } from './supabaseClient';
function TodoForm({ onAddTodo }) {
const [title, setTitle] = useState('');
async function handleSubmit(e) {
e.preventDefault();
if (!title.trim()) return;
const { error } = await supabase
.from('todos')
.insert([{ title, is_completed: false }])
.select()
.single();
Quảng cáo
300x250 In-Content Advertisement
if (error) console.error(error);
else {
onAddTodo();
setTitle('');
}
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={e => setTitle(e.target.value)}
placeholder="Nhập công việc mới..."
/>
<button type="submit">Thêm</button>
</form>
);
}
Tích hợp authentication
Để ứng dụng có tính cá nhân hóa, chúng ta cần tích hợp authentication. Supabase cung cấp sẵn UI components:
import { createClient } from '@supabase/supabase-js';
import { Authenticator, useAuth } from '@supabase/ui';
const supabase = createClient(
process.env.REACT_APP_SUPABASE_URL,
process.env.REACT_APP_SUPABASE_ANON_KEY
);
function App() {
const { user } = useAuth();
if (!user) {
return <Authenticator supabaseClient={supabase} />;
}
return (
<div>
<h1>Xin chào {user.email}</h1>
<TodoList />
<TodoForm />
</div>
);
}
Nâng cao tính năng
Filter và search
Thêm chức năng lọc công việc theo trạng thái:
const [filter, setFilter] = useState('all');
const filteredTodos = todos.filter(todo => {
if (filter === 'completed') return todo.is_completed;
if (filter === 'active') return !todo.is_completed;
return true;
});
Real-time updates
Supabase hỗ trợ real-time subscription, cho phép cập nhật dữ liệu tức thì:
useEffect(() => {
const subscription = supabase
.from('todos')
.on('*', (payload) => fetchTodos())
.subscribe();
return () => supabase.removeSubscription(subscription);
}, []);
Tối ưu hiệu năng
Debouncing input
Để tránh gửi quá nhiều request, chúng ta có thể sử dụng debouncing cho chức năng search:
const [searchTerm, setSearchTerm] = useState('');
const [searchTimeout, setSearchTimeout] = useState(null);
useEffect(() => {
if (searchTimeout) clearTimeout(searchTimeout);
const timer = setTimeout(() => {
// Thực hiện search
}, 300);
setSearchTimeout(timer);
}, [searchTerm]);
Lazy loading
Với danh sách dài, chúng ta có thể load dữ liệu từng phần:
const [page, setPage] = useState(1);
const [limit] = useState(10);
async function fetchTodos() {
const { data } = await supabase
.from('todos')
.select('*')
.range((page - 1) limit, page limit - 1);
}
Kết luận
Qua bài viết này, chúng ta đã cùng nhau xây dựng một ứng dụng todo hoàn chỉnh với Supabase và React. Từ việc thiết lập database, tạo các components React, tích hợp authentication, đến tối ưu hiệu năng, mỗi bước đều góp phần tạo nên một sản phẩm chất lượng.
Supabase thực sự là một lựa chọn tuyệt vời cho các dự án cần backend nhanh chóng mà không muốn phức tạp hóa kiến trúc. Kết hợp với React, chúng ta có thể tạo ra những ứng dụng web hiện đại, responsive và dễ bảo trì.
Hy vọng bài viết này đã cung cấp cho bạn cái nhìn tổng quan và hướng dẫn chi tiết để bắt đầu dự án của riêng mình. Chúc bạn thành công và hẹn gặp lại trong những bài viết tiếp theo!