Использование повторного выбора с полем даты на объектном редукторе - PullRequest
2 голосов
/ 22 марта 2020

У меня есть простое приложение со списком задач. Один из экранов представляет собой список «Сегодня и просрочено».

Редуктор задач выглядит следующим образом:

{
   "data": {
      123: {
         "id": 123,
         "summary": "blah blah",
         "dueDate": "2020-03-12",
         "completed": true
      },
      456: {
         "id": 456,
         "summary": "some other task",
         "dueDate": "2020-03-12",
         "completed": false
      }
   },
   "byId": [123, 456]
}

Редуктор моего списка выглядит следующим образом:

{
   "data": {
      919: {
         "id": 919,
         "name": "Today & Overdue"
      },
      818: {
         "id": 818,
         "summary": "My Cool List"
      }
   },
   "byId": [919, 818]
}

Вкл. Из списка «Сегодня и просрочено» мне нужно выбрать все задачи, для которых dueDate сегодня или старше. Я попытался использовать перезапуск, чтобы оптимизировать производительность экрана списка, с помощью:

# Get end of day today
const now = moment();
const endOfDay = Date.parse(now.endOf("day").utc(true).utcOffset(0).format());


const getTasksTodayOrOlder = (state) => Object.values(state.tasks.data).filter(task => Date.parse(task.dueDate) <= endOfDay);

Но похоже, что каждый раз, когда поле в данных задач изменяется (т. Е. Завершено или сводно), getTasksTodayOrOlder регенерирует селектор.

Это единственный способ сохранить кеш на редукторе tasks; что-то вроде byDueDate для отслеживания массива массивов сроков исполнения.


{
   "data": ...,
   "byId": ...,
   "byDueDate": {
       "2020-03-19": [112,123,141, ...],
       "2020-03-20": [922, 939, ...],
   }
}

Кэш даты выглядит как большая нагрузка и может выйти из строя c.

Каков рекомендуемый способ обработки повторного выбора, который будет:

  • Будет ли выполняться фильтрация для задач, которые должны быть выполнены сегодня или старше
  • Задачи, которые не выполнены

Ответы [ 2 ]

1 голос
/ 26 марта 2020

Если выходные данные селектора являются вычисляемым массивом, который использует Object.keys, Object.values ​​или Array.prototype.filter, вы можете запомнить его следующим образом:

const { createSelector, defaultMemoize } = Reselect;

const state = [
  { val: 1 },
  { val: 2 },
  { val: 3 },
  { val: 4 },
  { val: 5 },
  { val: 6 },
  { val: 7 },
];
//pass an array to memArray like [a,b], as long as a and b are the same
//  you will get the same array back even if the arrays themselves
//  are not the same like when you use filter, Object.values or Object.keys
const memArray = (() => {
  const mem = defaultMemoize((...args) => args);
  //pass the array that this function receives to a memoized function
  //  as separate arguments so if [a,b] is received it'll call
  //  memoized(a,b)
  return arr => mem(...arr);
})();//this is called an IIFE

const selectHigher = createSelector(
  state => state,
  (_, min) => min,
  (data, min) =>
    memArray(
      Object.values(data).filter(({ val }) => val > min)
    )
);
const one = selectHigher(state, 5);
const twoState = [...state, { val: 0 }];
const two = selectHigher(twoState, 5);
console.log('two is:',two);
console.log('one and two are equal', one === two);
const threeState = [...state, { val: 8 }];
const three = selectHigher(threeState, 5);
console.log('three is:',three);
console.log('three and two are equal', three === two);
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
0 голосов
/ 25 марта 2020

Что значит «регенерирует селектор»? Где вы используете этот селектор? Если вы используете его, например, в реагирующем функциональном компоненте через ловушку (useSelector), то:

// selectors

const now = moment();
const endOfDay = Date.parse(now.endOf("day").utc(true).utcOffset(0).format());

const getTasks = (state) => state.tasks.data;

const getTasksTodayOrOlder = createSelector(getTasks, tasks => 
  Object.values(tasks)
    .filter(task => Date.parse(task.dueDate) <= endOfDay)
    .map(({ id, dueDate }) => {id, dueDate});

// component

import { shallowEqual, useSelector } from 'react-redux';
.
.
.
const tasksTodayOrOlderList = useSelector(getTasksTodayOrOlder, shallowEqual);

Каждый раз, когда что-то в state.tasks.data изменяется, getTasksTodayOrOlder будет пересчитываться, но вы не будете получать рендер если предыдущее состояние tasksTodayOrOlderList равняется текущему выходу селектора getTasksTodayOrOlder (все значения внутри объектов равны), потому что мы передали второй аргумент shallowEqual нашей функции useSelector. Я использовал map для удаления «отслеживания» из ненужных свойств из нашего объекта данных.

И нам нужно разделить наш селектор на два, потому что нам нужно пересчитать только, если наш state.tasks.data изменится, а не когда какая-либо часть наше состояние меняется.

Кроме того, я думаю, что вы должны использовать endOfDay в качестве значения аргумента для селектора, потому что он динамический c.

...