🚀 Hướng Dẫn Sử Dụng Async Function trong React với TypeScript
Khi làm việc với TypeScript, một trong những nhầm lẫn phổ biến nhất là về các hàm async và kiểu trả về của chúng. Bài viết này sẽ giúp bạn hiểu rõ hơn về khái niệm này thông qua những ví dụ thực tế và các thực tiễn tốt nhất.
📖 Mục Lục
- Ví dụ Thực Tế: Kiểm Tra Trạng Thái Đăng Nhập Người Dùng
- Tại Sao Sử Dụng Promise và Không Phải là Boolean?
- Cách Sử Dụng Hàm Async
- Những Hiểu Lầm Thường Gặp
- Hàm Async với Arrow Functions
- Những Điều Cần Lưu Ý
- Câu Hỏi Thường Gặp (FAQ)
📝 Ví dụ Thực Tế: Kiểm Tra Trạng Thái Đăng Nhập Người Dùng
Giả sử bạn đang xây dựng một ứng dụng mà bạn cần kiểm tra xem người dùng đã đăng nhập hay chưa.
Phiên bản Đồng Bộ
typescript
function isUserLoggedIn(): boolean {
return true;
}
Phiên bản này hoạt động tốt nếu câu trả lời luôn có ngay lập tức.
Phiên bản Bất Đồng Bộ
Tuy nhiên, trong các ứng dụng thực tế, trạng thái đăng nhập thường đến từ một máy chủ hoặc cơ sở dữ liệu:
typescript
async function isUserLoggedIn(): Promise<boolean> {
const response = await fetch("/api/check-login");
if (!response.ok) {
return false;
}
const data = await response.json();
return data.loggedIn; // true hoặc false
}
Lưu ý:
- Kiểu trả về là
Promise<boolean>(không phảiboolean). - Mặc dù chúng ta trả về
truehoặcfalse, giá trị được bọc trong mộtPromise.
❓ Tại Sao Sử Dụng Promise và Không Phải là Boolean?
Mỗi hàm async trong TypeScript luôn trả về một Promise.
Vì vậy, đoạn mã sau:
typescript
return true;
thực chất là:
typescript
return Promise.resolve(true);
Đó là lý do tại sao kiểu trả về phải là Promise<boolean>.
Nếu bạn vô tình ghi chú nó là chỉ boolean:
typescript
async function isUserLoggedIn(): boolean {
return true;
}
Bạn sẽ nhận được lỗi biên dịch:
Type 'boolean' is not assignable to type 'Promise<boolean>'.
📝 Cách Sử Dụng Hàm Async
typescript
// Với await
const loggedIn = await isUserLoggedIn();
console.log(loggedIn); // true hoặc false
// Hoặc với .then()
isUserLoggedIn().then(status => console.log(status));
⚠️ Những Hiểu Lầm Thường Gặp
Một nghi ngờ phổ biến: “Nếu chúng ta đang đợi, có phải chúng ta đã quay lại thực thi đồng bộ?”
Câu trả lời: Không.
awaitchỉ tạm dừng thực thi trong hàm hiện tại cho đến khiPromiseđược giải quyết.- Nhưng nó không chặn vòng lặp sự kiện. Các tác vụ khác có thể tiếp tục chạy.
Vì vậy:
- Các hàm
asyncvẫn là bất đồng bộ dưới nắp. awaitchỉ cung cấp cú pháp giống như đồng bộ để mã sạch hơn.
Ví dụ:
typescript
async function main() {
console.log("Trước");
await isUserLoggedIn(); // tạm dừng *hàm này* thôi
console.log("Sau");
}
main();
console.log("Bên ngoài");
Thứ tự xuất ra:
Trước
Bên ngoài
Sau
Lưu ý:
Câu "Bên ngoài" được thực thi trong khi chúng ta đang “chờ”. Đó là sức mạnh của async/await.
📌 Hàm Async với Arrow Functions
async hoạt động mượt mà với các hàm mũi tên. Điều này rất phổ biến trong các dự án TypeScript và React hiện đại.
Ví dụ với hàm mũi tên
typescript
const isUserLoggedIn = async (): Promise<boolean> => {
const response = await fetch("/api/check-login");
const data = await response.json();
return data.loggedIn;
};
Trong một handler của React
typescript
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
const success = await isUserLoggedIn();
console.log("Trạng thái đăng nhập:", success);
};
Với các phương thức mảng
Hàm mũi tên và async thường đi cùng với các thao tác trên mảng:
typescript
const urls = ["/a", "/b", "/c"];
const fetchAll = async () => {
const results = await Promise.all(
urls.map(async url => {
const res = await fetch(url);
return res.json();
})
);
console.log(results);
};
💡 Những Điều Cần Lưu Ý
- Hàm
asyncluôn trả vềPromise<T>, không bao giờ chỉ làT. - Trả về một giá trị thô tự động bọc nó trong
Promise.resolve(value). awaittạm dừng cục bộ nhưng không chặn vòng lặp sự kiện.- Hàm mũi tên async thường xuất hiện trong callback, handler và các phương thức mảng.
- Sử dụng
asynckhi làm việc với API, cơ sở dữ liệu, hoặc bất kỳ tác vụ bất đồng bộ nào — điều này giúp bảo vệ chữ ký hàm của bạn trong tương lai.
📌 Câu Hỏi Thường Gặp (FAQ)
1. Hàm async có thể không trả về gì không?
Có, bạn có thể không trả về giá trị nào từ hàm async, nó sẽ trả về Promise<void>.
2. Có thể sử dụng async trong các hàm không phải là hàm mũi tên không?
Có, bạn có thể sử dụng async với bất kỳ hàm nào, bao gồm cả hàm thông thường.
3. Tại sao không sử dụng await trong một hàm không phải là async?
Sẽ dẫn đến lỗi, vì await chỉ có thể được sử dụng trong các hàm async.
Hy vọng rằng bài viết này đã giúp bạn hiểu rõ hơn về các hàm async trong React với TypeScript và cách áp dụng chúng một cách hiệu quả trong dự án của bạn.