Trong bài viết này, mình sẽ giải thích cách để tạo 1 custom hook giúp cho việc fetch dữ liệu (thông qua API) và làm thế nào để chúng ta có thể tái sử dụng chúng trong các components khác nhau.
Hooks là 1 khái niệm mới được React thêm vào từ phiên bản 16.8. Bạn có thể tìm hiểu thêm trên trang chủ của React với link sau:
https://reactjs.org/docs/hooks-intro.html
const useFetch = (url, options) => {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const resp= await fetch(url, options);
const data = await resp.json();
setData(data);
} catch (e) {
setData([]);
setError(e);
}
}
fetchData();
}, []);
return { data, error }
}
Cùng giải thích đoạn code trên.
Chúng ta đã tạo ra 1 custom hook tên là useFetch (lưu ý tất cả các Hook function đều bắt đầu bởi use ), 1 function cơ bản với 2 tham số đầu vào là url và options; kết quả trả về là 1 object gồm 2 state là data và error.
Trong hook trên mình sử dụng 2 hooks khác của react đó là useState và useEffect.
useState là 1 hook cho phép bạn có những biến state trong functional components
useEffect là 1 hook cho phép bạn có những side effects từ bên trong functional components (ví dụ như cập nhật DOM, tạo 1 cuộc gọi bất đồng bộ , …). Nó nhận đầu vào 2 tham giá, đầu tiên là 1 hàm callback, tham số thứ 2 là mảng các phụ thuộc. Mỗi khi có sự thay đổi, cập nhật của 1 trong số các giá trị phụ thuộc thì ham callback sẽ được gọi đến.
Trong hàm useFetch của chúng ta sẽ không có phụ thuộc nào, điều đó có nghĩa là hàm callback của chúng ta sẽ chỉ được gọi 1 lần (bạn có thể hình dung nó giống như cách mà hàm componentDidMount hoạt động trong class component). Trong hàm callback chúng ta sẽ fetch dữ liệu với 1 hàm bất đồng bộ.
Để sử dụng thêm biến loading cho việc hiển thị giao diện, bạn có thể thêm loading state vào trong hook trên như sau:
const useFetch = (url, options) => {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
try {
const resp= await fetch(url, options);
const data = await resp.json();
setData(data);
} catch (e) {
setData([]);
setError(e);
}
setIsLoading(false);
}
fetchData();
}, []);
return { data, error, isLoading }
}
Sau khi add xong loading state, chúng ta sẽ thử xem làm thế nào để sử dụng nó trong các components khác nhau.
Giả sử chúng ta có 1 component là Component1.js và muốn sử dụng useFetch hook vừa tạo ở trên. Cách sử dụng như dưới đây
const Component1 = () => {
const { data, error, isLoading } = useFetch('someUrl', { method: 'get'});
if (isLoading ) {
//Show a loader here because fetch is still going on.
// return <Loader />
}
if (error) {
// Show some error message
// return <ErrorState />
}
return (
// Do something with data
)
}
Như vậy bạn cũng có thể sử dụng useFetch hook trên ở 1 Component khác bằng cách triển khai code như trên, mục đích là có thể tái sử dụng mà không cần phải viết lại đoạn code fetch data. Giá trị data, error, isLoading được sử dụng trong các components triển khai một cách độc lập.
Link gốc:
Bình luận