Recoilの公式ドキュメントをgoogle翻訳するとコードまで翻訳されてしまうのが面倒なのでQiitaにまとめてみます。
追々追加していきます。
目次
- 前書き ① ② ③ ④
- 基本チュートリアル ⑤ ⑥ ⑦
- ガイド
- ⑧非同期データクエリ
- ⑨非同期state・同期state
- ⑩Stateの永続性
- APIリファレンス
- Core ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ㉑ ㉒ ㉓ ㉔ ㉕ ㉖ ㉗
- 実用(utils) ㉘ ㉙ ㉚ ㉛ ㉜ ㉝ ㉞ ㉟
※全目次は一番下にあります
非同期state・同期state
重要なお知らせ
このAPIは現在開発中であり、今後変更される予定です。お楽しみに...
Recoil atoms は局所的な応用stateを表します。
アプリケーションは、RESTful APIなどを介してリモートまたはサーバー側のstateを持っている場合もあります。
リモートstateをRecoil atomと同期することを検討してください。これにより、useRecoilState()
hookを使用してReactコンポーネントからstateに簡単にアクセスしたり、そのstateを他の派生state selectorのデータフローグラフへの入力として使用したりできます。
データベースまたはサーバーに読み取り専用データを問い合わせる場合は、非同期selectorの使用を検討してください。
ローカルStateの例
この例では、フレンドステータスをローカルstateとしてのみ提供します。
const currentUserIDState = atom({
key: 'CurrentUserID',
default: null,
});
function CurrentUserInfo() {
const [currentUserID] = useRecoilState(currentUserIDState);
return <div>Current User: {currentUserID}</div>;
}
サーバからstateを同期
リモートstateの非同期変更を登録し、それに合わせてatom値を更新することができます。これは、通常 React useEffect()
hookまたはその他の一般的なライブラリを使用して実行できます。
function CurrentUserIDSubscription() {
const setCurrentUserID = useSetRecoilState(currentUserIDState);
useEffect(() => {
RemoteStateAPI.subscribeToCurrentUserID(setCurrentUserID);
// Specify how to cleanup after this effect
return function cleanup() {
RemoteServerAPI.unsubscribeFromCurrentUserID(setCurrentUserID);
};
}, []);
return null;
}
function MyApp() {
return (
<RecoilRoot>
<CurrentUserIDSubscription />
<CurrentUserInfo />
</RecoilRoot>
);
}
1つの場所で複数のatomの同期を処理する場合は、State Persistenceパターンも使用できます。
双方向同期
stateを同期して、ローカルの変更がサーバー上で更新されるようにすることもできます。
これは単純化した例です。フィードバックのループを避けるように注意してください。
function CurrentUserIDSubscription() {
const [currentUserID, setCurrentUserID] = useRecoilState(currentUserIDState);
const knownServerCurrentUserID = useRef(currentUserID);
// Subscribe server changes to update atom state
useEffect(() => {
function handleUserChange(id) {
knownServerCurrentUserID.current = id;
setCurrentUserID(id);
}
RemoteStateAPI.subscribeToCurrentUserID(handleUserChange);
// Specify how to cleanup after this effect
return function cleanup() {
RemoteServerAPI.unsubscribeFromCurrentUserID(handleUserChange);
};
}, [knownServerCurrentUserID]);
// Subscribe atom changes to update server state
useEffect(() => {
if (currentUserID !== knownServerCurrentUserID.current) {
knownServerCurrentID.current = currentUserID;
RemoteServerAPI.updateCurrentUser(currentUserID);
}
}, [currentUserID, knownServerCurrentUserID.current]);
return null;
}
パラメータを使用したstateの同期
atomFamilyヘルパーを使用して、パラメータに基づいてローカルstateを同期することもできます。
このhookの例の呼び出しごとにサブスクリプションが作成されるため、冗長な使用を避けるように注意してください。
const friendStatusState = atomFamily({
key: 'Friend Status',
default: 'offline',
});
function useFriendStatusSubscription(id) {
const setStatus = useSetRecoilState(friendStatusState(id));
useEffect(() => {
RemoteStateAPI.subscribeToFriendStatus(id, setStatus);
// Specify how to cleanup after this effect
return function cleanup() {
RemoteServerAPI.unsubscribeFromFriendStatus(id, setStatus);
};
}, []);
}
データフローグラフ
リモートstateを表すためにatomを使用する利点は、他の派生stateの入力として使用できることです。
次の例では、現在のサーバのstateに基づいて、現在のユーザと友人のリストを表示します。サーバが現在のユーザを変更すると、リスト全体が再描画されます。友人のステータスだけを変更すると、そのリストエントリだけが再描画されます。リスト項目をクリックすると、現在のユーザがローカルに変更され、サーバのstateが更新されます。
const userInfoQuery = selectorFamily({
key: 'UserInfoQuery',
get: userID => async ({get}) => {
const response = await myDBQuery({userID});
if (response.error) {
throw response.error;
}
return response;
},
});
const currentUserInfoQuery = selector({
key: 'CurrentUserInfoQuery',
get: ({get}) => get(userInfoQuery(get(currentUserIDState)),
});
const friendColorState = selectorFamily({
key: 'FriendColor',
get: friendID => ({get}) => {
const [status] = get(friendStatusState(friendID));
return status === 'offline' ? 'red' : 'green';
},
});
function FriendStatus({friendID}) {
useFriendStatusSubscription(friendID);
const [status] = useRecoilState(friendStatusState(friendID));
const [color] = useRecoilState(friendColorState(friendID));
const [friend] = useRecoilState(userInfoQuery(friendID));
return (
<div style={{color}}>
Name: {friend.name}
Status: {status}
</div>
);
}
function CurrentUserInfo() {
const {name, friendList} = useRecoilValue(currentUserInfoQuery);
const setCurrentUserID = useSetRecoilState(currentUserIDState);
return (
<div>
<h1>{name}</h1>
<ul>
{friendList.map(friendID =>
<li key={friend.id} onClick={() => setCurrentUserID(friend.id)}>
<React.Suspense fallback={<div>Loading...</div>}>
<FriendStatus friendID={friendID} />
</React.Suspense>
</li>
)}
</ul>
</div>
);
}
function MyApp() {
return (
<RecoilRoot>
<ErrorBoundary>
<React.Suspense fallback={<div>Loading...</div>}>
<CurrentUserIDSubscription />
<CurrentUserInfo />
</React.Suspense>
</ErrorBoundary>
</RecoilRoot>
);
}
参考サイト
・公式ドキュメント
・React ドキュメント useEffect()
・みらい翻訳
全目次
- 前書き
- ①動機
- ②コアコンセプト
- ③インストール
- ④入門
- 基本チュートリアル
- ⑤概要
- ⑥Atoms
- ⑦Selectors
- ガイド
- ⑧非同期データクエリ
- ⑨非同期state・同期state
- ⑩Stateの永続性
- APIリファレンス
-
Core
• ⑪ <RecoilRoot />
• State
・ ⑫atom()
・ ⑬selector()
・ ⑭Loadable
・ ⑮useRecoilState()
・ ⑯useRecoilValue()
・ ⑰useSetRecoilState()
・ ⑱useResetRecoilState()
・ ⑲useRecoilValueLoadable()
・ ⑳useRecoilStateLoadable()
・ ㉑isRecoilValue()
• Snapshots
・ ㉒Snapshot
・ ㉓useRecoilTransactionObserver()
・ ㉔useRecoilSnapshot()
・ ㉕useGotoRecoilSnapshot()
• ㉖useRecoilCallback()
• 雑録(Misc)
・ ㉗useRecoilBridgeAcrossReactRoots()
-
実用(utils)
• ㉘atomFamily()
• ㉙selectorFamily()
• ㉚constSelector()
• ㉛errorSelector()
• ㉜waitForAll()
• ㉝waitForAny()
• ㉞waitForNone()
• ㉟noWait()