編集
私は寝ていて、この場合の簡単な(しかしおそらくまだ不要な)解決策を夢見ていました(真剣に笑)。フィルター結果でプリミティブ型を返す必要があるため、2 番目のセレクターJSON.stringify()
でそれを行うことができます。JSON.parse()
次のテスト スイートはパスします。
const state = {
list: [
{ id: 1, active: true },
{ id: 2, active: false },
{ id: 3, active: false },
{ id: 4, active: false }
]
}
const getFilteredListIds = createSelector(
(state) => JSON.stringify(state.list.filter((object) => !!object.active)),
(filteredList) => JSON.parse(filteredList).map((object) => object.id)
)
expect(getFilteredListIds.recomputations()).toEqual(0)
expect(getFilteredListIds(state)).toEqual([1])
expect(getFilteredListIds.recomputations()).toEqual(1)
expect(getFilteredListIds(state)).toEqual([1])
expect(getFilteredListIds.recomputations()).toEqual(1)
const newState = {
list: [
...state.list,
{ id: 5, active: false } // should not change subset
]
}
expect(getFilteredListIds(newState)).toEqual([1]) // subset didn't change
expect(getFilteredListIds.recomputations()).toEqual(1) // pass :)
ただし、ユース ケースによっては、呼び出しごとにフィルター処理するよりも遅くなる場合があります。そのパフォーマンスをテストしたら、私たちと共有してください。
最初の投稿
コメントで言ったように、あなたが実装した方法はcreateSelector
役に立たなくなります。
const state = {
list: [
{ id: 1, active: true },
{ id: 2, active: false },
{ id: 3, active: false },
{ id: 4, active: false }
]
}
const getFilteredListIds = createSelector(
(state) => state.list.filter((object) => !!object.active),
(filteredList) => filteredList.map((object) => object.id)
)
expect(getFilteredListIds.recomputations()).toEqual(0)
expect(getFilteredListIds(state)).toEqual([1])
expect(getFilteredListIds.recomputations()).toEqual(1)
expect(getFilteredListIds(state)).toEqual([1])
expect(getFilteredListIds.recomputations()).toEqual(1) // fail
まず、この最初の問題を解決するためにいくつかの調整を行いました。
const state = {
list: [
{ id: 1, active: true },
{ id: 2, active: false },
{ id: 3, active: false },
{ id: 4, active: false }
]
}
const getList = (state) => state.list
// it makes filter only happen if state.list changes
const getFilteredList = createSelector(
getList,
(list) => list.filter((object) => !!object.active)
)
const getFilteredListIds = createSelector(
getFilteredList,
(filteredList) => filteredList.map((object) => object.id)
)
expect(getFilteredListIds.recomputations()).toEqual(0)
expect(getFilteredListIds(state)).toEqual([1])
expect(getFilteredListIds.recomputations()).toEqual(1)
expect(getFilteredListIds(state)).toEqual([1])
expect(getFilteredListIds.recomputations()).toEqual(1)
// everything pass
あなたの質問は有効です:
オブジェクトまたはフィルタリングされたリストに変更がある場合、新しいオブジェクトのみを取得する可能性はありますか?
あなたが欲しいのはこれですよね?
const newState = {
list: [
...state.list,
{ id: 5, active: false } // should not change subset
]
}
expect(getFilteredListIds(newState)).toEqual([1]) // subset didn't change
expect(getFilteredListIds.recomputations()).toEqual(1) // fail
しかし、最後の行は 2 になるため失敗しrecomputations()
ます。
これを解決する唯一の方法は、状態のメモ化されたfilteredList
部分を作成することですが、それは奇妙かもしれません。