在寫業務的過程中,我們總是會遇到這樣的需求,在請求時顯示一個 loading,然後請求結束後展示資料。以一個是不是 vip 的場景為例,如果不加入 loading 狀態,頁面可能在未請求的時候顯示非 vip,資料請求完成之後,發現是 vip,再改成 vip。這樣無疑體驗較差,但是我們又不希望一直使用 useState 來宣告 loading 狀態,這無疑是乏味的:
const [loading, setLoading] = useState(false);
...
所以,不如使用 hooks 來封裝這部分邏輯,來實現一個 useLoading hook。
在寫這個 hook 之前,我們要先理清楚這個 hook 的入參和出參。我們希望這個 hook 有這樣的效果,我們傳入一個請求的函式,得到這個函式是否在 loading,以及一個包裝後的請求函式。程式碼如下:
const [isLoading, wrappedAjax] = useLoading(ajax);
實現
直接上程式碼:
import { useState, useCallback } from "react";
export default function useLoading(req) {
const [loading, setLoading] = useState(false);
const wrapReq = useCallback(
(...args) => {
setLoading(true);
return req(...args).then((data) => {
setLoading(false);
return Promise.resolve(data);
}).catch((reason) => {
setLoading(false);
return Promise.reject(reason);
});
},
[req]
);
return [loading, wrapReq];
}
程式碼也很簡單,就是對原先的 api 請求進行了包裝,在呼叫前,設定 loading 為 true,拿到資料之後,設定 loading 為 false。呼叫方式如下:
const [loading, req] = useLoading(checkVip);
useEffect(() => {
req().then(({ vip }) => {
console.log(vip);
setVip(vip);
}).catch((err) => alert(err));
}, [req]);
下面是一個簡單的 demo(沒看到效果請點選重新整理按鈕)。可以看到,當不設定 loading 狀態的時候,頁面是由 no vip 跳到 vip 的,體驗是比較差的。
why not React Query
當我們只是需要一個 loading 狀態,而又不想寫重複的 useState 來管理 loading 狀態時,上面這個小 hook 就顯得更輕量了。但是如果需要一整套完整的解決方案,使用 React Query 則是更好的選擇。(本文完)