2016-06-20 3 views
5

Я использую reselect для получения частей моего состояния redux. У меня есть список объектов в моем состоянии. Один из моих subselector для моего создать селектор является функцией фильтра этого списка:Как использовать повторный выбор в списке изменений, когда объекты одинаковы?

state => state.list.filter(filterFunction) 

Так я передать это моей createSelector:

Эта функция фильтра возвращает подмножество из моих объектов в списке , Поэтому, если список изменяется, повторно выбрать всегда возвращает новый объект, даже если подмножество не изменилось, потому что список не совпадает (полностью правильно).

Есть ли возможность получить только новый объект, если есть изменения в объектах или в отфильтрованном списке?

+0

Это происходит потому, что 'filter' (ваш селектор ввода) всегда возвращает новый объект. AFAIK, 'reselect' сравнивает результат селекторов ввода с помощью' === '(' state.list.filter (filterFunction) === state.list.filter (filterFunction) '), и он всегда будет' false', даже если список не изменяется. –

+0

Чтобы пояснить, как вы реализовали это, 'createSelector' оказывается бесполезным. Он будет пересчитывать каждый вызов, даже если состояние не изменяется, поскольку селектор ввода (фильтр) всегда возвращает новый объект. –

ответ

3

В конце концов я была идея, которая могла бы работать:

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(
    ...order.map(id => list[id]), 
    selector, 
); 

...order.map(id => list[id]), Линия будет распространяться на объекты в качестве аргументов. Они будут одинаковыми, если порядок-массив не будет изменен. Поэтому я могу сгенерировать новый объект только с объектами, указанными в заказе.

0

EDIT

я спал и мечтал (серьезно ха-ха) с простым (но, возможно, до сих пор ненужным) решением для этого случая. Вы должны вернуть примитивный тип в результат фильтра, так что вы можете 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 :) 

Однако, в зависимости от вашего варианта использования, он может быть медленным, чем фильтр при каждом вызове. Если вы проверите эту производительность, поделитесь с нами.


ПЕРВЫЙ ПОСТ

Как я уже говорил в comments, как вы реализовали, что делает 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 

Но последняя линия потерпит неудачу, потому что recomputations() будет 2.

Единственный способ я вижу в решении это делает memoized filteredList часть вашего состояния, но это может быть странно.

 Смежные вопросы

  • Нет связанных вопросов^_^