Hiểu về optimistic UI và React useOptimistic Hook

Milliseconds có thể tạo nên hoặc phá hỏng trải nghiệm người dùng, vì sự chậm trễ có thể khiến họ rời khỏi trang web của chúng ta. Một chiến lược đang được chú ý nhờ khả năng mang lại các tương tác nhanh chóng và nhạy bén là mẫu giao diện lạc quan (Optimistic UI pattern). Mẫu này cho phép chúng ta cập nhật giao diện người dùng ngay lập tức sau khi người dùng hoàn thành một hành động, dựa trên giả định rằng các hoạt động nền sẽ thành công. Phương pháp này làm tăng cảm giác về tốc độ của ứng dụng và cải thiện đáng kể trải nghiệm người dùng bằng cách cung cấp phản hồi ngay tức thì.

Hiểu về Optimistic UI và Hook useOptimistic của React
Trong bài viết này, chúng ta sẽ khám phá Hook mới của React là useOptimistic và cách nó có thể giúp chúng ta triển khai các cập nhật giao diện lạc quan để làm cho ứng dụng của chúng ta cảm giác nhanh hơn và nhạy bén hơn.

React useOptimistic Hook là gì?
Hook useOptimistic là một tính năng mạnh mẽ hiện có sẵn trong phiên bản Canary của React. Nó cho phép chúng ta hiển thị một trạng thái khác trong khi một hành động bất đồng bộ, chẳng hạn như yêu cầu mạng, đang diễn ra. Điều này đặc biệt quan trọng trong những trường hợp người dùng mong đợi phản hồi tức thì cho các hành động của họ, chẳng hạn như khi gửi biểu mẫu hoặc bình luận trên mạng xã hội.

Bằng cách triển khai Hook useOptimistic, các ứng dụng có thể cập nhật giao diện người dùng ngay lập tức, mang lại trải nghiệm người dùng liền mạch và hấp dẫn. Hãy cùng tìm hiểu với một ví dụ:

const [optimisticComments, postComment] = useOptimistic(commentsFromServer, addComment);
  • optimisticComments: Đây là trạng thái Optimistic, được khởi tạo với giá trị từ commentsFromServer. Nó hiển thị danh sách các bình luận hiện có trên một bài đăng, phản ánh ngay lập tức mọi hành động của người dùng.
  • postComment: Đây là hàm dispatch mà chúng ta gọi để áp dụng mutation được định nghĩa trong addComment. Hàm này cập nhật optimisticComments một cách Optimistic khi người dùng thêm một bình luận.
  • commentsFromServer: Đây là nguồn dữ liệu chính, đại diện cho danh sách các bình luận đã được xác nhận lấy từ server. Nếu giá trị này thay đổi (ví dụ, sau khi lấy dữ liệu mới từ server), optimisticComments cũng sẽ cập nhật để đảm bảo tính nhất quán.
  • addComment: Đây là logic mutation sẽ được áp dụng cho optimisticComments khi postComment được gọi. Nó xác định cách thêm một bình luận mới vào danh sách một cách Optimistic.

Xét về hiệu quả của nhà phát triển, React đã giới thiệu Hook useOptimistic được tùy chỉnh cho mẫu giao diện này. Việc cập nhật giao diện lạc quan đảm bảo rằng người dùng không phải chờ đợi phản hồi từ server, điều này là rất quan trọng để duy trì trải nghiệm người dùng mượt mà. Khi người dùng thực hiện một hành động, useOptimistic phản ánh ngay lập tức các thay đổi trạng thái trước khi server phản hồi.

Hook này quản lý trạng Optimistic bằng cách ban đầu giả định rằng API sẽ phản hồi thành công. Nếu API phản hồi thành công, trạng thái giả định sẽ được duy trì. Trong trường hợp API thất bại, trạng thái sẽ trở lại trạng thái ban đầu. Sự cân bằng này là rất quan trọng để duy trì tính toàn vẹn của dữ liệu trong khi cung cấp trải nghiệm người dùng nhanh chóng và nhạy bén.

Bằng cách sử dụng Hook useOptimistic, các nhà phát triển có thể tạo ra những ứng dụng cảm giác tức thì và hấp dẫn hơn, giữ cho người dùng luôn tham gia và hài lòng với hiệu suất.

Một ví dụ đơn giản: Bình luận trên một bài đăng
Hãy tưởng tượng một nền tảng mạng xã hội nơi người dùng có thể xem các bài đăng của người khác. Khi người dùng nhấn nút Gửi, ứng dụng sẽ đợi phản hồi từ server trước khi cập nhật giao diện người dùng. Sự chậm trễ này có thể làm cho ứng dụng cảm giác chậm chạp.

Giả sử chúng ta đã có một server được thiết lập với các tệp cần thiết, hãy tiến hành triển khai chức năng Optimistic:

import { useState } from 'react';
import { useOptimistic } from 'react';
function CommentButton({ postId }) {
const [comments, setComments] = useOptimistic([]);
const [newComment, setNewComment] = useState('');
const [error, setError] = useState('');
const handleCommentSubmit = async () => {
setError(''); // Xóa mọi lỗi trước đó
const optimisticNewComment = { id: Date.now(), text: newComment, status: 'sending' };
setComments([...comments, optimisticNewComment]);  // Cập nhật danh sách bình luận một cách Optimistic
try {
const response = await api.postComment(postId, newComment);
const updatedComments = comments.map(comment =>
comment.id === optimisticNewComment.id ? { ...comment, status: 'sent' } : comment
);
setComments(updatedComments); // Cập nhật trạng thái bình luận thành 'sent'
} catch (error) {
const filteredComments = comments.filter(comment => comment.id !== optimisticNewComment.id);
setComments(filteredComments);
setError('Không thể đăng bình luận. Vui lòng thử lại.');
}
};
return (
<div>
<input 
type="text"
value={newComment}
onChange={(e) => setNewComment(e.target.value)}
placeholder="Viết bình luận..."
/>
<button onClick={handleCommentSubmit} disabled={!newComment.trim()}>
Đăng bình luận
</button>
{comments.map(comment => (
<div key={comment.id}>
{comment.text} {comment.status === 'sending' && <span>(Đang gửi...)</span>}
</div>
))}
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
);
}
export default CommentButton;

Trong đoạn mã này, chúng ta đang khởi tạo Optimistic. Biến trạng thái optimisticComments chứa danh sách các bình luận, bao gồm mọi cập nhật Optimistic (các bình luận xuất hiện ngay lập tức khi người dùng thêm chúng, trước khi được xác nhận từ server). Nó bắt đầu dưới dạng một mảng trống [].

postComment là một hàm mà chúng ta sử dụng để cập nhật optimisticComments một cách Optimistic. Nó nhận một bình luận mới và thêm nó vào danh sách các bình luận hiện có. Hàm mutation (comments, newComment) => [...comments, newComment] xác định cách cập nhật danh sách bình luận khi thêm một bình luận mới. Nó tạo ra một mảng mới chứa tất cả các bình luận hiện có và bình luận mới.

Để gửi một bình luận một cách Optimistic, trước tiên chúng ta sẽ tạo một bình luận Optimistic. optimisticNewComment là một đối tượng bình luận mới với một ID tạm thời, văn bản từ trường nhập liệu, và trạng thái là sending. Đối tượng này đại diện cho bình luận mà người dùng vừa thêm.

Sau đó, để đạt được cập nhật Optimistic, chúng ta sẽ sử dụng postComment(optimisticNewComment), hành động này sẽ cập nhật danh sách optimisticComments để bao gồm bình luận mới ngay lập tức. Điều này mang lại cho người dùng phản hồi tức thì rằng bình luận của họ đã được thêm.

Sau đó, khối try sẽ cố gắng gửi bình luận mới đến server bằng cách sử dụng api.postComment(postId, newComment). Nếu server xác nhận bình luận đã được thêm, trạng thái của optimisticNewComment sẽ được cập nhật thành sent. Danh sách bình luận sẽ được cập nhật để phản ánh trạng thái mới này. Nếu cuộc gọi đến server thất bại, khối catch sẽ xóa bình luận Optimistic khỏi optimisticComments và đặt một thông báo lỗi để thông báo cho người dùng rằng bình luận không thể được đăng.

Khi chúng ta chạy ứng dụng và nhấn nút Đăng bình luận, nó sẽ trông như thế này:

Lưu ý cách nó hiển thị “Đang gửi” cùng với bình luận — đó chính là điều mà Hook useOptimistic làm. Nó đăng bình luận trong khi vẫn đang chờ yêu cầu mạng hoàn tất.

Optimistic UI vs. Các phương pháp truyền thống
Bằng cách triển khai mẫu giao diện Optimistic, các ứng dụng có thể giả lập phản hồi tức thì bằng cách cập nhật giao diện người dùng ngay khi người dùng tương tác, điều này đặc biệt quan trọng trong các môi trường tương tác liền mạch như mạng xã hội.

Các cập nhật giao diện truyền thống dựa vào thời gian phản hồi từ server, khiến người dùng phải chờ đợi lâu và làm cho ứng dụng cảm giác chậm chạp. Giao diện Optimistic biến đổi trải nghiệm này bằng cách cập nhật giao diện trước khi server phản hồi, hiển thị ngay kết quả mong đợi của hành động người dùng — như việc nhìn thấy một bình luận xuất hiện ngay khi nhấn.

ấn “Đăng bình luận”. Điều này làm cho ứng dụng cảm giác nhanh hơn nhiều.

Tóm lại, mẫu giao diện Optimistic giúp cải thiện trải nghiệm người dùng bằng cách giảm thiểu sự chậm trễ và mang lại cảm giác tức thì. Bằng cách sử dụng Hook useOptimistic của React, chúng ta có thể dễ dàng triển khai chiến lược này, mang lại trải nghiệm người dùng mượt mà hơn và tăng cường sự tương tác với người dùng.

Chúng ta đã đi qua các khái niệm và lợi ích của Optimistic UI và React Hook useOptimistic. Khi triển khai các kỹ thuật này, bạn có thể tạo ra các ứng dụng cảm giác nhanh hơn và nhạy bén hơn. Những ứng dụng này không chỉ cung cấp phản hồi tức thì cho người dùng mà còn giúp nâng cao trải nghiệm tổng thể của họ.

Hãy cân nhắc sử dụng useOptimistic trong dự án React tiếp theo của bạn để tận dụng mẫu giao diện Optimistic và mang lại trải nghiệm tốt nhất cho người dùng!

Để lại một bình luận

22/08/2024