Selectorをコンポーネントから切り離す
要はコンポーネントへ参照透過性を持たせるということ コンポーネントからStoreの依存を消して純粋なViewコンポーネントにする
code:tsx
// getUserArticlesがSelector
// StoreからViewに必要なデータを取得する処理を押し込む
const selectUserArticles = ({ store = store, userId}) => {
const user = /* storeとuserIdからuserを引いてくる */
const articles = /* storeとuserからarticlesを引いてくる */
return {
...user,
articles
}
}
// Selectorはpropsのデフォルト値にすることで、このコンポーネントはstoreとは疎結合になる
const UserArticlesContainer = ({ userId, selectUserArticles = selectUserArticles}) => {
const articles = useSelector(selectUserArticles({ userId }))
return <UserArticlesView articles={articles }/>
}
const UserArticlesView = /*~*/
// モックしやすいしLifting state upもできる
<UserArticlesContainer userId={1} articles={/*~*/} />
若干冗長なのがネックか
モックするのが目的ならテスト設計とのトレードオフかも code:tsx
const userArticlesState = selectorFamily({
key: "userArticles",
get: (userId:number) => ({get}) => {
const user = get(usersState(userId))
return user.articles
}
})
const UserArticlesContainer = ({ userId, userArticlesState = userArticlesState}) => {
const articles = useRecoilValue(userArticlesState(userId))
return <UserArticlesView articles={articles }/>
}
const UserArticlesView = /*~
こっちなら非同期処理も対応できるのでコロケーションしやすいメリットがある 以下のPrivateコンポーネント
https://pbs.twimg.com/media/FbP3zpiacAATXQd.pnghttps://pbs.twimg.com/media/FbP32rVacAcZ8P1.png