前面幾天的介紹,希望大家對 Recoil 的使用,有些基本的認識了。如果有說明不清楚、錯誤的地方,還請留言跟我說,我會儘速調整、修正。
今天會跟大家分享非同步狀態如何與 Recoil 結合。
使用者可以透過瀏覽器切換 user id,但需要透過 user id 向伺服器請求 user 其他相關的資訊,我們希望這些 user 的狀態能在我們的 App 當中,供所有元件共享。
我們藉由一個 Promise 配 setTimeout 模擬請求伺服器的 async request ,透過帶參數user id給Promise function,我們可以取回對應的 user object。
function getData(id) {
const data = [
{
id: 0,
name: "Lala"
},
...
{
id: 5,
name: "stan"
}
];
return new Promise((resolve) => {
setTimeout(() => {
resolve(data[id]);
}, 500);
});
}
假設我們預設一開始拿到的 userID 是 1 , 我們透過 Recoil API atom
,將 userID 存入我們的 Recoil 。
export const currentUserIDState = atom({
key: "CurrentUserID",
default: 1
});
建立一組 Select 的元件,使我們能切換 user ID ,透過 useRecoilState 帶入需要使用的 shared state ,在這裡也就是我們的 currentUserIDState
,如此便能取得這個 state 與其 setter function。
function CurrentUserSelect() {
const [userID, setUserID] = useRecoilState(currentUserIDState);
const handleChangeUser = ({ target: { value } }) => {
setUserID(value);
};
return (
<>
<span>切換User ID: </span>
<select value={userID} onChange={handleChangeUser}>
<option value={1}>user id 1</option>
<option value={2}>user id 2</option>
<option value={3}>user id 3</option>
<option value={4}>user id 4</option>
<option value={5}>user id 5</option>
</select>
</>
);
}
昨天我們透過 selector 裡面的 get function 取得 Recoil 內部的某個狀態,並計算出其他狀態,回傳存入 Recoil,這次也同樣是藉由 selector 取得當前的 userID ,並向伺服器發出請求,獲取 User Object 然後存入 Recoil。
在步驟一當中,我們定義了 user object 是 {id:0,name:'Ken'}
的形式。如今我們需要取得這個 user object 後,將這個 user name 存入 Recoil。
export const currentUserNameState = selector({
key: "CurrentUserName",
get: async ({ get }) => {
const user = await getData(get(currentUserIDState));
return user.name;
}
});
昨天的 get 屬性是放入一個同步的方法,今天我們在這方法前面加入 async ,使他成為非同步的方法。
其中我們向伺服器請求資料 (* 在這裡就是 getData(id) *)
codesandbox demo
getData(id)這個 id 從何而來呢?就是使用 get(currentUserIDState) 獲得Recoil當前的 user ID。
並且在這selector 儲存使用者姓名,因此我們 return user.name
現在我們會先看到編譯報錯說我們需要使用 <Suspense>
,因為我們向遠端發送請求時,我們不希望非同步的請求阻斷了 React 的渲染,因請透過 <Suspense>
通知 React ,並且定義了這段時間我們希望呈現的 Loading 畫面。
因此在我們的 App 加上 Suspense
<Suspense fallback={<h1>loading......</h1>}>
<CurrentUserSelect />
<CurrentUserInfo />
</Suspense>
最後,我們就能使用在元件裡調用我們的 user name
function CurrentUserInfo() {
const userName = useRecoilValue(currentUserNameState);
return <div>User name :{userName} </div>;
}
<Suspense>
使用,若想要更客製化 Loading 可使用 useRecoilValueLoadable
API (之後分享)