How to use reselect on a changing list, when the objects are the same?
Asked Answered
E

2

13

I use reselect to get parts of my redux state. i have a list of objects in my state. One of my subselector for my create selector is a filter function of this list:

state => state.list.filter(filterFunction)

So i pass this to my createSelector:

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

This filter function returns a subset of my objects in the list. So if the list changes, reselect always returns a new object, even if the subset didn't changed, because the list isn't the same (fully correct).

is there a possibility to get only a new object if there are changes to the objects or the filtered list?

Equestrian answered 20/6, 2016 at 8:47 Comment(2)
It happens because filter (your input selector) always returns a new object. AFAIK, reselect compares the result of input selectors through === (state.list.filter(filterFunction) === state.list.filter(filterFunction)) and it will always be false even if the list doesn't change.Padauk
To clarify, the way you've implemented that, createSelector ends up being useless. It will recompute on every call even if the state doesn't change, because the input selector (filter) always returns a new object.Padauk
E
8

After all i had an idea which could work:

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,
  )
);

The line ...order.map(id => state => state.list[id]), will spread the objects as arguments. They will be the same if the order-array will not be changed. So i can generate a new Object with only the Objects listed in the order.

The evaluation function of the first create Selector only gets called if the order array changes. If this happens, a recalculation of the result is necessary anyway. So this is fine. The second one only recalculates if it gets new values. The values are functions that are generated out of the order array. Even if the list object changes (due to more entries or smaller changes on other objects that are not considered in the current list), the pointer to the objects of the order array stays the same. So we always get a the same objects as arguments to our second evaluation function. This prevents an unwanted update.

Equestrian answered 9/11, 2016 at 14:42 Comment(0)
B
0

Just use re-reselect.

re-reselect is a lightweight wrapper around Reselect meant to enhance selectors with deeper memoization and cache management.

Bullion answered 5/11, 2019 at 10:0 Comment(2)
Looks like she is using re-select...?Patinous
No, Maksim is suggesting a library called re-reselect, not reselect (easy to misread the name -- I did too at first). Details about how it applies to this specific problem would have been useful in the reply though.Unstrained

© 2022 - 2025 — McMap. All rights reserved.