Redux 当对象相同时,如何在更改列表上使用“重新选择”?

Redux 当对象相同时,如何在更改列表上使用“重新选择”?,redux,react-redux,reselect,Redux,React Redux,Reselect,我使用“重新选择”来获取部分redux状态。我有一个处于我的状态的对象列表。创建选择器的子选择器之一是此列表的筛选函数: state => state.list.filter(filterFunction) 因此,我将其传递给我的createSelector: createSelector( state => state.list.filter(filterFunction), (subsetOfObjects) => subsetOfObjects.map(doSo

我使用“重新选择”来获取部分redux状态。我有一个处于我的状态的对象列表。创建选择器的子选择器之一是此列表的筛选函数:

state => state.list.filter(filterFunction)
因此,我将其传递给我的createSelector:

createSelector(
  state => state.list.filter(filterFunction),
  (subsetOfObjects) => subsetOfObjects.map(doSomething)
);
此筛选函数返回列表中“我的对象”的子集。因此,如果列表发生更改,即使子集没有更改,重新选择也会始终返回一个新对象,因为列表不相同(完全正确)

如果对象或筛选列表发生更改,是否有可能仅获取新对象?

编辑

我睡着了,梦见了一个简单的(但可能还是不必要的)解决方案。您必须在筛选结果上返回一个基元类型,以便在第二个选择器上执行
JSON.stringify()
it和
JSON.parse()
。以下测试套件通过:

const state={
名单:[
{id:1,active:true},
{id:2,active:false},
{id:3,active:false},
{id:4,活动: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)
常数newState={
名单:[
…state.list,
{id:5,active:false}//不应更改子集
]
}
expect(getFilteredListIds(newState)).toEqual([1])//子集未更改
expect(getFilteredListIds.recomputations()).toEqual(1)//pass:)
然而,根据您的使用情况,它可能比每次调用的过滤器慢。如果您测试了该性能,请与我们分享


第一篇文章

正如我在中所说,您的实现方式使得
createSelector
毫无用处

const state={
名单:[
{id:1,active:true},
{id:2,active:false},
{id:3,active:false},
{id:4,活动:false}
]
}
const getFilteredListIds=createSelector(
(state)=>state.list.filter((object)=>!!object.active),
(filteredList)=>filteredList.map((对象)=>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 state={
名单:[
{id:1,active:true},
{id:2,active:false},
{id:3,active:false},
{id:4,活动:false}
]
}
const getList=(state)=>state.list
//仅当state.list发生更改时,才会进行筛选
const getFilteredList=createSelector(
获取列表,
(list)=>list.filter((object)=>!!object.active)
)
const getFilteredListIds=createSelector(
getFilteredList,
(filteredList)=>filteredList.map((对象)=>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={
名单:[
…state.list,
{id:5,active:false}//不应更改子集
]
}
expect(getFilteredListIds(newState)).toEqual([1])//子集未更改
expect(getFilteredListIds.recomputations()).toEqual(1)//失败
但是最后一行将失败,因为
重新计算()
将为2


解决这个问题的唯一方法是将记忆的
过滤器列表
作为您的状态的一部分,但这可能会很奇怪。

毕竟我有一个想法,可以奏效:

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数组对象的指针也保持不变。所以我们总是得到一个与第二个求值函数的参数相同的对象。这可以防止不必要的更新。

只需使用即可


重新选择是一个围绕重新选择的轻量级包装,旨在通过更深入的记忆和缓存管理增强选择器。

之所以发生这种情况,是因为
过滤器
(您的输入选择器)总是返回一个新对象。好的,
reselect
通过
==
state.list.filter(filterFunction)==state.list.filter(filterFunction)
)比较输入选择器的结果,即使列表没有更改,它也总是
false
。为了澄清一下,您实现它的方式,
createSelector
。即使状态没有改变,它也会在每次调用时重新计算,因为输入选择器(筛选器)总是返回一个新对象。看起来她在使用重新选择…?不,Maksim建议使用一个名为重新选择的库,而不是重新选择库(很容易误读名称——我一开始也这么做了)。