Я создаю этот компонент фильтра меню:
с помощью этого меню на практике вы можете фильтровать список карточек, не стесняясь выбирать разные фильтры одновременно; возвращенный список карточек будет результатом всех выбранных опций.
чтобы сгенерировать такой фильтр, я фильтрую по отфильтрованной опции и так далее, другими словами, так:
return props.tasks.filter(x => {
if (props.key.includes('task-status')) {
return props.status.some(status => x['task-status'] === status)
}
return true
}).filter(x => {
if (props.key.includes('task-priority')) {
return props.priority.reduce((vres, val) => vres.concat(val), []).some(priority => x['task-priority'] === priority)
}
return true;
}).filter(x => {
if (props.key.includes('task-actual-owner')) {
return props.users.some(user => x['task-actual-owner'] === user)
}
return true;
}).filter(x => {
if (props.key.includes('task-expiration-time')) {
if (x['task-expiration-time'] === null) {
return false;
}
const f = props.expiration.flat();
return x['task-expiration-time']['java.util.Date'] >= f[0] && x['task-expiration-time']['java.util.Date'] <= f[1]
}
return true;
})
Итак, весь список карточек происходит из этого массива объектов:
array = [
{
"task-id": 142,
"task-name": "Task",
"task-subject": "",
"task-description": "",
"task-status": "Ready",
"task-priority": 0,
"task-is-skipable": false,
"task-actual-owner": null,
"task-created-by": null,
"task-created-on": {
"java.util.Date": 1606322625000
},
"task-activation-time": {
"java.util.Date": 1606322625000
},
"task-expiration-time": {
"java.util.Date": 1200832320000
},
"task-proc-inst-id": 187,
"task-proc-def-id": "businessProcess.main",
"task-container-id": "businessProcess_1.0.1-SNAPSHOT",
"task-parent-id": -1,
"correlation-key": "187",
"process-type": 1
},
{
"task-id": 141,
"task-name": "Task",
"task-subject": "",
"task-description": "",
"task-status": "InProgress",
"task-priority": 9,
"task-is-skipable": false,
"task-actual-owner": "john.doe",
"task-created-by": null,
"task-created-on": {
"java.util.Date": 1606322577000
},
"task-activation-time": {
"java.util.Date": 1606322577000
},
"task-expiration-time": {
"java.util.Date": 1674200580000
},
"task-proc-inst-id": 186,
"task-proc-def-id": "businessProcess.main",
"task-container-id": "businessProcess_1.0.1-SNAPSHOT",
"task-parent-id": -1,
"correlation-key": "186",
"process-type": 1
},
{
"task-id": 140,
"task-name": "Task",
"task-subject": "",
"task-description": "",
"task-status": "Reserved",
"task-priority": 6,
"task-is-skipable": false,
"task-actual-owner": "peter.griffin",
"task-created-by": null,
"task-created-on": {
"java.util.Date": 1606322524000
},
"task-activation-time": {
"java.util.Date": 1606322524000
},
"task-expiration-time": {
"java.util.Date": 1863598080000
},
"task-proc-inst-id": 185,
"task-proc-def-id": "businessProcess.main",
"task-container-id": "businessProcess_1.0.1-SNAPSHOT",
"task-parent-id": -1,
"correlation-key": "185",
"process-type": 1
},
{
"task-id": 139,
"task-name": "Task",
"task-subject": "",
"task-description": "",
"task-status": "Reserved",
"task-priority": 0,
"task-is-skipable": false,
"task-actual-owner": "homer.simpson",
"task-created-by": null,
"task-created-on": {
"java.util.Date": 1606322446000
},
"task-activation-time": {
"java.util.Date": 1606322446000
},
"task-expiration-time": null,
"task-proc-inst-id": 184,
"task-proc-def-id": "businessProcess.main",
"task-container-id": "businessProcess_1.0.1-SNAPSHOT",
"task-parent-id": -1,
"correlation-key": "184",
"process-type": 1
},
{
"task-id": 138,
"task-name": "Task",
"task-subject": "",
"task-description": "",
"task-status": "Reserved",
"task-priority": 0,
"task-is-skipable": false,
"task-actual-owner": "jim.carrey",
"task-created-by": null,
"task-created-on": {
"java.util.Date": 1606322412000
},
"task-activation-time": {
"java.util.Date": 1606322412000
},
"task-expiration-time": null,
"task-proc-inst-id": 183,
"task-proc-def-id": "businessProcess.main",
"task-container-id": "businessProcess_1.0.1-SNAPSHOT",
"task-parent-id": -1,
"correlation-key": "183",
"process-type": 1
}
]
и массив объектов, созданный с помощью нескольких вариантов выбора, может быть таким (например):
[
{
key: "task-status",
label: "Waiting For",
status: "Ready"
},
{
key: "task-status",
label: "Picked Up",
status: "Reserved"
}
{
key: "task-priority",
label: "Low",
priority: [0, 1, 2, 3, 4]
},
{
key: "task-actual-owner",
label: "John Doe",
owner: "john.doe"
},
{
key: "task-expiration-time",
expiration: [1611598726000, 1611609526000]
}
];
Все работает правильно, но я пытаюсь найти способ рефакторинга первой функции … (return props.tasks.filter(x => { ...
) Есть ли способ добиться этого?
1 ответ
Есть две основные вещи, которые вы можете сделать, чтобы немного очистить его:
- Вместо того, чтобы связывать кучу
.filter()
s вместе, создайте список функций фильтра, которые вы хотите использовать, а затем используйте только выбранные. - Вы можете немного разбить функцию, вытащив и назвав каждую из функций фильтра. Это может упростить понимание с первого взгляда, какую логику выполняет ваша функция.
Вот один из способов закодировать его после применения этих двух идей. (Следующее не проверено, но должно дать представление)
function applyFilters(props) {
const filters = [];
if (props.key.includes('task-status')) {
filters.push(createFilterFor.status(props));
}
if (props.key.includes('task-priority')) {
filters.push(createFilterFor.priority(props));
}
if (props.key.includes('task-actual-owner')) {
filters.push(createFilterFor.owner(props));
}
if (props.key.includes('task-expiration-time')) {
filters.push(createFilterFor.expirationTime(props));
}
return props.tasks.filter(combineFilters(filters));
}
const combineFilters = filters => (
entry => filters.every(filter => filter(entry))
);
const createFilterFor = {
status: ({ status }) => (
task => status.some(statusText => task['task-status'] === statusText)
),
priority: ({ priority }) => (
task => priority.flat(1).some(priorityText => task['task-priority'] === priorityText)
),
owner: ({ users }) => (
task => users.some(user => task['task-actual-owner'] === user)
),
expirationTime: ({ expiration }) => (
task => {
if (!task['task-expiration-time']) return false;
const taskExpiration = task['task-expiration-time']['java.util.Date'];
const [start, end] = expiration.flat();
return taskExpiration >= start && taskExpiration <= end;
}
),
};
Если вы обнаружите, что добавляете множество функций фильтра, которые следуют этому шаблону, вы можете добавить уровень абстракции, который позволит вам удалить цепочку if-then, но это сделает код более нечитаемым и менее гибким.
function applyFilters(props) {
const filters = Object.entries(createFilterFor)
.filter(([key]) => props.keys.includes(key))
.map(([, createFilter]) => createFilter(props));
return props.tasks.filter(combineFilters(filters));
}
const combineFilters = filters => (
entry => filters.every(filter => filter(entry))
);
const createFilterFor = {
'task-status': ({ status }) => (
task => status.some(statusText => task['task-status'] === statusText)
),
'task-priority': ({ priority }) => (
task => priority.flat(1).some(priorityText => task['task-priority'] === priorityText)
),
'task-actual-owner': ({ users }) => (
task => users.some(user => task['task-actual-owner'] === user)
),
'task-expiration-time': ({ expiration }) => (
task => {
if (!task['task-expiration-time']) return false;
const taskExpiration = task['task-expiration-time']['java.util.Date'];
const [start, end] = expiration.flat();
return taskExpiration >= start && taskExpiration <= end;
}
),
};
Обновить
Судя по отзывам @ DiddyO, мне кажется, я лучше понимаю, какова цель этого вопроса. Вот обновленная, гораздо более упрощенная версия, которая должна делать то, что просили (при условии, что я правильно понял комментарий).
(Еще раз, это непроверено и может содержать пару ошибок, но должно дать представление о том, как выполнить эту задачу)
const applyFilters = props => (
props.tasks.filter(createFilterFromProps(props))
);
const createFilterFromProps = props => (
entry => Object.entries(filters).every(
([key, filter]) => !props.key.includes(key) || filter(props, entry[key])
)
);
const filters = {
'task-status': ({ status }, taskStatus) => status.some(statusText => taskStatus === statusText),
'task-priority': ({ priority }, taskPriority) => priority.flat(1).some(priorityText => taskPriority === priorityText),
'task-actual-owner': ({ users }, actualOwner) => users.some(user => user === actualOwner),
'task-expiration-time': ({ expiration }, taskExpiration) => {
if (!taskExpiration) return false;
const [start, end] = expiration.flat();
return taskExpiration['java.util.Date'] >= start && taskExpiration['java.util.Date'] <= end;
},
};
```
Большое спасибо … действительно полезно, я подумал о другом, но я не уверен, я подумал о создании функции, которая не требует нескольких проходов фильтра. Что-то, что может уменьшить массив объектов фильтра до логического значения и использовать его в одном фильтре, просто объединяя пользователей, приоритет, статус и так далее, и используя ключ из объекта obj. Я не хочу использовать жестко запрограммированные строки, такие как «статус задачи», потому что я уже определил ключ в объекте фильтра.
— Дидди О.
@DiddyO. Я обновил ответ новым фрагментом кода, который, надеюсь, должен делать то, что вы хотите.
— Скотти Джеймисон
большое спасибо за твою помощь. Действительно полезно
— Дидди О.