12

reselect を使用して、redux 状態の一部を取得します。私は自分の状態にあるオブジェクトのリストを持っています。作成セレクターのサブセレクターの 1 つは、このリストのフィルター関数です。

state => state.list.filter(filterFunction)

だから私はこれを私のcreateSelectorに渡します:

createSelector(
  state => state.list.filter(filterFunction),
  (subsetOfObjects) => subsetOfObjects.map(doSomething)
);

このフィルター関数は、リスト内のオブジェクトのサブセットを返します。したがって、リストが変更された場合、リストが同じではない (完全に正しい) ため、サブセットが変更されていなくても、reselect は常に新しいオブジェクトを返します。

オブジェクトまたはフィルタリングされたリストに変更がある場合、新しいオブジェクトのみを取得する可能性はありますか?

4

3 に答える 3

7

結局のところ、私はうまくいくアイデアを持っていました:

const list = {


object1: {
    id: 'object1',
  },
  object2: {
    id: 'object2',
  },
  object3: {
    id: 'object3',
  },
};

const order = ['object1', 'object3'];

const selector = (...args) => args.reduce((prev, curr) => ({...prev, [curr.id]: curr}), {});

createSelector(
  state => state.order,
  order => createSelector(
    ...order.map(id => state => state.list[id]),
    selector,
  )
);

この行...order.map(id => state => state.list[id]),は、オブジェクトを引数として展開します。order-array が変更されない場合、それらは同じになります。したがって、順番にリストされているオブジェクトのみを使用して新しいオブジェクトを生成できます。

最初の create Selector の評価関数は、順序配列が変更された場合にのみ呼び出されます。これが発生した場合、とにかく結果の再計算が必要です。だからこれでいい。2 番目のものは、新しい値を取得した場合にのみ再計算します。値は、順序配列から生成される関数です。リスト オブジェクトが変更された場合でも (現在のリストで考慮されていない他のオブジェクトのより多くのエントリまたは小さな変更が原因で)、順序配列のオブジェクトへのポインターは同じままです。したがって、2 番目の評価関数への引数として常に同じオブジェクトを取得します。これにより、不要な更新が防止されます。

于 2016-11-09T14:42:41.323 に答える
-2

編集

私は寝ていて、この場合の簡単な(しかしおそらくまだ不要な)解決策を夢見ていました(真剣に笑)。フィルター結果でプリミティブ型を返す必要があるため、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部分を作成することですが、それは奇妙かもしれません。

于 2016-06-20T12:08:13.030 に答える