Khám phá truyền luồng phản hồi React Server Action cho các biểu mẫu. Tìm hiểu cách xây dựng các biểu mẫu nhanh hơn, đáp ứng tốt hơn để cải thiện trải nghiệm người dùng.
Truyền Luồng Phản Hồi React Server Action: Phản Hồi Form Tăng Dần để Nâng Cao UX
React Server Actions giới thiệu một sự thay đổi mô hình mạnh mẽ trong cách chúng ta xử lý các hoạt động phía máy chủ trong các ứng dụng React. Một trong những tính năng thú vị nhất là khả năng truyền luồng phản hồi một cách tăng dần, cho phép chúng ta cung cấp phản hồi ngay lập tức cho người dùng ngay cả trước khi toàn bộ hoạt động hoàn tất. Điều này đặc biệt có lợi cho các biểu mẫu, nơi chúng ta có thể tạo ra trải nghiệm người dùng nhạy bén và hấp dẫn hơn bằng cách cập nhật giao diện người dùng khi có dữ liệu.
Hiểu về React Server Actions
Server Actions là các hàm bất đồng bộ chạy trên máy chủ, được khởi tạo từ các component React. Chúng mang lại nhiều lợi thế so với các lời gọi API truyền thống:
- Bảo mật được cải thiện: Server Actions chạy trực tiếp trên máy chủ, giảm nguy cơ lộ dữ liệu nhạy cảm hoặc logic cho phía client.
- Giảm mã lặp: Chúng loại bỏ sự cần thiết của các route API riêng biệt và logic lấy dữ liệu ở phía client.
- Hiệu suất nâng cao: Chúng có thể tận dụng render phía máy chủ (SSR) và bộ nhớ đệm để có thời gian tải ban đầu nhanh hơn và hiệu suất được cải thiện.
- An toàn kiểu dữ liệu: Với TypeScript, Server Actions cung cấp an toàn kiểu dữ liệu từ đầu đến cuối, đảm bảo tính nhất quán của dữ liệu giữa client và máy chủ.
Sức Mạnh của Truyền Luồng Phản Hồi
Việc gửi biểu mẫu truyền thống thường bao gồm việc gửi tất cả dữ liệu đến máy chủ, chờ phản hồi, rồi sau đó cập nhật giao diện người dùng tương ứng. Điều này có thể dẫn đến sự chậm trễ cảm nhận được, đặc biệt đối với các biểu mẫu phức tạp hoặc kết nối mạng chậm. Truyền luồng phản hồi cho phép máy chủ gửi dữ liệu trở lại cho client theo từng phần, giúp chúng ta cập nhật giao diện người dùng một cách tăng dần khi có dữ liệu.
Hãy tưởng tượng một biểu mẫu tính toán một mức giá phức tạp dựa trên đầu vào của người dùng. Thay vì chờ toàn bộ quá trình tính toán hoàn tất, máy chủ có thể truyền luồng các kết quả trung gian trở lại cho client, cung cấp phản hồi thời gian thực cho người dùng. Điều này có thể cải thiện đáng kể trải nghiệm người dùng và làm cho ứng dụng có cảm giác nhạy bén hơn.
Triển Khai Phản Hồi Form Tăng Dần với Server Actions
Hãy cùng xem qua một ví dụ về cách triển khai phản hồi form tăng dần với React Server Actions.
Ví dụ: Một Công Cụ Chuyển Đổi Tiền Tệ Thời Gian Thực
Chúng ta sẽ tạo một biểu mẫu chuyển đổi tiền tệ đơn giản cung cấp cập nhật tỷ giá hối đoái theo thời gian thực khi người dùng nhập số tiền.
1. Thiết lập Server Action
Đầu tiên, chúng ta định nghĩa Server Action xử lý việc chuyển đổi tiền tệ.
// server/actions.ts
'use server';
import { unstable_cache } from 'next/cache';
async function getExchangeRate(fromCurrency: string, toCurrency: string): Promise<number> {
// Mô phỏng việc lấy tỷ giá từ một API bên ngoài
console.log(`Đang lấy tỷ giá cho ${fromCurrency} sang ${toCurrency}`);
await new Promise(resolve => setTimeout(resolve, 500)); // Mô phỏng độ trễ mạng
if (fromCurrency === 'USD' && toCurrency === 'EUR') return 0.92;
if (fromCurrency === 'EUR' && toCurrency === 'USD') return 1.09;
if (fromCurrency === 'USD' && toCurrency === 'JPY') return 145;
if (fromCurrency === 'JPY' && toCurrency === 'USD') return 0.0069;
throw new Error(`Không tìm thấy tỷ giá cho ${fromCurrency} sang ${toCurrency}`);
}
export const convertCurrency = async (prevState: any, formData: FormData) => {
const fromCurrency = formData.get('fromCurrency') as string;
const toCurrency = formData.get('toCurrency') as string;
const amount = Number(formData.get('amount'));
try {
if (!fromCurrency || !toCurrency || isNaN(amount)) {
return { message: 'Vui lòng cung cấp đầu vào hợp lệ.' };
}
// Mô phỏng việc truyền luồng phản hồi
await new Promise(resolve => setTimeout(resolve, 250));
const exchangeRate = await unstable_cache(
async () => getExchangeRate(fromCurrency, toCurrency),
[`exchange-rate-${fromCurrency}-${toCurrency}`],
{ tags: [`exchange-rate-${fromCurrency}-${toCurrency}`] }
)();
await new Promise(resolve => setTimeout(resolve, 250));
const convertedAmount = amount * exchangeRate;
return { message: `Số tiền đã chuyển đổi: ${convertedAmount.toFixed(2)} ${toCurrency}` };
} catch (e: any) {
console.error(e);
return { message: 'Không thể chuyển đổi tiền tệ.' };
}
};
Trong ví dụ này, Server Action convertCurrency
lấy tỷ giá hối đoái (được mô phỏng với độ trễ) và tính toán số tiền đã chuyển đổi. Chúng tôi đã thêm các độ trễ nhân tạo bằng cách sử dụng setTimeout
để mô phỏng độ trễ mạng và minh họa hiệu ứng truyền luồng.
2. Triển khai Component React
Tiếp theo, chúng ta tạo component React sử dụng Server Action.
// app/page.tsx
'use client';
import { useState, useTransition } from 'react';
import { convertCurrency } from './server/actions';
import { useFormState } from 'react-dom';
export default function CurrencyConverter() {
const [fromCurrency, setFromCurrency] = useState('USD');
const [toCurrency, setToCurrency] = useState('EUR');
const [amount, setAmount] = useState('');
const [isPending, startTransition] = useTransition();
const [state, formAction] = useFormState(convertCurrency, { message: '' });
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
startTransition(() => {
formAction(new FormData(event.target as HTMLFormElement));
});
};
return (
<div>
<h2>Công Cụ Chuyển Đổi Tiền Tệ Thời Gian Thực</h2>
<form action={handleSubmit}>
<label htmlFor="fromCurrency">Từ:</label>
<select id="fromCurrency" name="fromCurrency" value={fromCurrency} onChange={(e) => setFromCurrency(e.target.value)}>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
<option value="JPY">JPY</option>
</select>
<label htmlFor="toCurrency">Đến:</label>
<select id="toCurrency" name="toCurrency" value={toCurrency} onChange={(e) => setToCurrency(e.target.value)}>
<option value="EUR">EUR</option>
<option value="USD">USD</option>
<option value="JPY">JPY</option>
</select>
<label htmlFor="amount">Số tiền:</label>
<input
type="number"
id="amount"
name="amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<button type="submit" disabled={isPending}>
{isPending ? 'Đang chuyển đổi...' : 'Chuyển đổi'}
</button>
</form>
<p>{state.message}</p>
</div>
);
}
Các điểm chính:
- Chúng ta sử dụng hook
useFormState
để quản lý trạng thái biểu mẫu và gọi Server Action. - Trạng thái
isPending
từuseTransition
vô hiệu hóa nút gửi và hiển thị thông báo "Đang chuyển đổi..." trong khi hành động đang chạy, cung cấp phản hồi cho người dùng. - Hàm
formAction
được trả về bởiuseFormState
tự động xử lý việc gửi biểu mẫu và cập nhật trạng thái với phản hồi từ Server Action.
3. Hiểu về Các Cập Nhật Tăng Dần
Khi người dùng gửi biểu mẫu, hàm handleSubmit
được gọi. Nó tạo ra một đối tượng FormData
từ biểu mẫu và chuyển nó cho hàm formAction
. Server Action sau đó được thực thi trên máy chủ. Do các độ trễ nhân tạo được thêm vào trong Server Action, bạn sẽ quan sát thấy những điều sau:
- Nút gửi thay đổi thành "Đang chuyển đổi..." gần như ngay lập tức.
- Sau một khoảng trễ ngắn (250ms), mã mô phỏng việc lấy tỷ giá hối đoái.
- Số tiền đã chuyển đổi được tính toán và kết quả được gửi lại cho client.
state.message
trong component React được cập nhật, hiển thị số tiền đã chuyển đổi.
Điều này minh họa cách truyền luồng phản hồi cho phép chúng ta cung cấp các cập nhật trung gian cho người dùng khi có dữ liệu, dẫn đến trải nghiệm người dùng nhạy bén và hấp dẫn hơn.
Lợi ích của Phản Hồi Form Tăng Dần
- Cải thiện trải nghiệm người dùng: Cung cấp phản hồi ngay lập tức cho người dùng, làm cho ứng dụng có cảm giác nhạy bén hơn và ít ì ạch hơn.
- Giảm độ trễ cảm nhận được: Bằng cách hiển thị kết quả trung gian, người dùng cảm nhận quá trình nhanh hơn, ngay cả khi tổng thời gian hoạt động vẫn như cũ.
- Tăng cường sự tương tác: Giữ chân người dùng bằng cách cung cấp các cập nhật thời gian thực và ngăn họ rời bỏ biểu mẫu do cảm thấy chậm trễ.
- Tăng tỷ lệ chuyển đổi: Một trải nghiệm người dùng mượt mà và nhạy bén hơn có thể dẫn đến tỷ lệ chuyển đổi cao hơn, đặc biệt đối với các biểu mẫu phức tạp.
Các Kỹ Thuật Nâng Cao
1. Sử dụng `useOptimistic` để Cập Nhật Giao Diện Tức Thì
Hook useOptimistic
cho phép bạn cập nhật giao diện người dùng một cách lạc quan trước khi Server Action hoàn tất. Điều này có thể cung cấp thời gian phản hồi cảm nhận được nhanh hơn nữa, vì giao diện người dùng phản ánh kết quả mong đợi ngay lập tức.
import { useOptimistic } from 'react';
function MyComponent() {
const [optimisticState, addOptimistic] = useOptimistic(
initialState,
(state, newUpdate) => {
// Trả về trạng thái mới dựa trên bản cập nhật
return { ...state, ...newUpdate };
}
);
const handleClick = async () => {
addOptimistic({ someValue: 'cập nhật lạc quan' });
await myServerAction();
};
return (
<div>
<p>{optimisticState.someValue}</p>
<button onClick={handleClick}>Cập nhật</button>
</div>
);
}
Trong ví dụ về công cụ chuyển đổi tiền tệ, bạn có thể cập nhật lạc quan số tiền đã chuyển đổi dựa trên tỷ giá hối đoái hiện tại, cung cấp một bản xem trước ngay lập tức cho người dùng trước khi phép tính thực tế hoàn tất trên máy chủ. Nếu máy chủ trả về lỗi, bạn có thể hoàn tác cập nhật lạc quan đó.
2. Triển khai Xử Lý Lỗi và Cơ Chế Dự Phòng
Điều quan trọng là phải triển khai xử lý lỗi và các cơ chế dự phòng mạnh mẽ để xử lý các trường hợp Server Action thất bại hoặc kết nối mạng bị gián đoạn. Bạn có thể sử dụng khối try...catch
trong Server Action để bắt lỗi và trả về một thông báo lỗi phù hợp cho client.
// server/actions.ts
export const convertCurrency = async (prevState: any, formData: FormData) => {
// ...
try {
// ...
} catch (error: any) {
console.error(error);
return { message: 'Đã xảy ra lỗi khi chuyển đổi tiền tệ. Vui lòng thử lại sau.' };
}
};
Ở phía client, bạn có thể hiển thị thông báo lỗi cho người dùng và cung cấp các tùy chọn để thử lại hoạt động hoặc liên hệ hỗ trợ.
3. Lưu Cache Tỷ Giá để Tăng Hiệu Suất
Việc lấy tỷ giá từ một API bên ngoài có thể là một điểm nghẽn về hiệu suất. Để cải thiện hiệu suất, bạn có thể lưu cache tỷ giá bằng cách sử dụng một cơ chế lưu trữ như Redis hoặc Memcached. unstable_cache
từ Next.js (như đã sử dụng trong ví dụ) cung cấp một giải pháp lưu cache tích hợp sẵn. Hãy nhớ vô hiệu hóa cache định kỳ để đảm bảo rằng tỷ giá hối đoái luôn được cập nhật.
4. Những Lưu Ý về Quốc Tế Hóa (i18n)
Khi xây dựng các ứng dụng cho đối tượng toàn cầu, điều quan trọng là phải xem xét đến quốc tế hóa (i18n). Điều này bao gồm:
- Định dạng số: Sử dụng các định dạng số phù hợp cho các ngôn ngữ khác nhau (ví dụ: sử dụng dấu phẩy hoặc dấu chấm làm dấu phân cách thập phân).
- Định dạng tiền tệ: Hiển thị các ký hiệu và định dạng tiền tệ theo ngôn ngữ của người dùng.
- Định dạng ngày và giờ: Sử dụng các định dạng ngày và giờ phù hợp cho các ngôn ngữ khác nhau.
- Bản địa hóa: Dịch giao diện người dùng sang các ngôn ngữ khác nhau.
Các thư viện như Intl
và react-intl
có thể giúp bạn triển khai i18n trong các ứng dụng React của mình.
Ví Dụ và Trường Hợp Sử Dụng Thực Tế
- Thương mại điện tử: Hiển thị chi phí vận chuyển và ước tính giao hàng theo thời gian thực khi người dùng thêm sản phẩm vào giỏ hàng.
- Ứng dụng tài chính: Cung cấp báo giá cổ phiếu và cập nhật danh mục đầu tư theo thời gian thực.
- Đặt vé du lịch: Hiển thị giá vé máy bay và tình trạng còn chỗ theo thời gian thực.
- Trực quan hóa dữ liệu: Truyền luồng cập nhật dữ liệu đến các biểu đồ và đồ thị.
- Công cụ cộng tác: Hiển thị các cập nhật thời gian thực cho tài liệu và dự án.
Kết Luận
Truyền luồng phản hồi React Server Action mang lại một cách mạnh mẽ để nâng cao trải nghiệm người dùng của các ứng dụng React của bạn. Bằng cách cung cấp các phản hồi form tăng dần, bạn có thể tạo ra các biểu mẫu nhanh hơn, nhạy bén hơn và hấp dẫn hơn, giữ chân người dùng và cải thiện tỷ lệ chuyển đổi. Bằng cách kết hợp truyền luồng phản hồi với các kỹ thuật như cập nhật lạc quan và lưu cache, bạn có thể xây dựng những trải nghiệm người dùng thực sự đặc biệt.
Khi React Server Actions tiếp tục phát triển, chúng ta có thể mong đợi nhiều tính năng và khả năng mạnh mẽ hơn nữa sẽ xuất hiện, giúp đơn giản hóa hơn nữa việc phát triển các ứng dụng web phức tạp và năng động.
Tìm Hiểu Thêm
Hướng dẫn này cung cấp một cái nhìn tổng quan toàn diện về truyền luồng phản hồi React Server Action và ứng dụng của nó vào các phản hồi form tăng dần. Bằng cách hiểu các khái niệm và kỹ thuật được thảo luận ở đây, bạn có thể tận dụng tính năng mạnh mẽ này để xây dựng các ứng dụng web nhanh hơn, nhạy bén hơn và hấp dẫn hơn.