基于多个过滤器的过滤器阵列

时间:2020-09-27 02:19:19

标签: javascript arrays reactjs filter

我有一个表,希望对其应用多个过滤器。我当前的代码将按电子邮件或状态进行过滤,但我希望两者同时执行,以便用户优化结果。

我尝试在&&变量中添加||而不是filteredInvoices

我允许用户选择要使用的过滤器,并将其存储在useState的对象中。我还会跟踪过滤器处于活动状态还是非活动状态。

const [filter, setFilter] = useState({active: false})

用户选择了其过滤器的过滤器对象如下所示:

filter: {active: true, customerEmail: 'johndoe@gmail.com', status: 'open'}

当用户将此过滤器应用于表时,更改过滤器后,我在useEffect中调用了一个名为updateFilter()的函数。然后,这会将过滤后的数组设置为在return中进行迭代的状态。

const updateFilter = () => {
    const filteredInvoices = invoices.filter((inv) => {
        const emailMatch = filter.customerEmail && inv.customerEmail.toLowerCase().includes(filter.customerEmail.toLowerCase())
        const statusMatch = inv.status === filter.status
        return emailMatch || statusMatch
    })
    setListToRender(filteredInvoices)
}

useEffect(() => {
    if (filter.active) {
        updateFilter()
    }

}, [filter])

正在过滤的状态是一个对象数组。

如何通过添加到过滤器对象中的多种条件进行过滤?

是否有一个通用的设计可以使我向过滤器对象添加其他过滤器,并且它也可以正常工作?

例如-johndoe@gmail.com有10张发票-3张未结,4张已付款和3张作废。如果过滤器对象如下所示:

如何过滤以仅显示该未清客户的发票。

提前感谢您的任何建议!

3 个答案:

答案 0 :(得分:2)

由于您不仅希望能够匹配特定的键值对,而且可能还需要做一些诸如在过滤之前对值进行预处理(例如将电子邮件转换为小写字母的操作),然后再进行通用操作方法可能最适合您。你可以有这样的东西

const updateFilter = () => {
    const filteredInvoices = invoices.filter(invoice => {
    let validInvoice = true;
    
    for (const [key, value] of Object.entries(filter)) {
      if (Array.isArray(value)) {
        if (!value.includes(invoice[key])) {
          validInvoice = false;
        }
      }
      else if (typeof value === 'function') {
        if (!value(invoice[key])) {
          validInvoice = false;
        }
      }
      else {
        if (value !== invoice[key]) validInvoice = false;
      }
    }
    
    return validInvoice;
  });
  
  setListToRender(filteredInvoices)
}

使用这种方法,您可以拥有一个包含原始值,函数或数组的过滤器。像这样:

const filter = {
    // This will check if the invoice 'active' property is true
    active: true,
    // This will check that the status is NOT equal to pending
    status: (status) => status !== 'pending',
    // This will check if the email matches ANY of these values
    email: ['john@doe.com', 'cho@mumma.com']
};

与简单的键/值匹配方法相比,此方法可带来更多细微差别,并使您可以更深入地自定义过滤器

答案 1 :(得分:1)

您可以使用filterevery数组方法进行过滤。

const invoices = [
 {active: false , customerEmail: 'joedoe@gmail.com', status: 'paid'},
 {active: false , customerEmail: 'sam@gmail.com', status: 'paid'},
 {active: true , customerEmail: 'michael@gmail.com', status: 'void'},
 {active: true , customerEmail: 'adam@gmail.com', status: 'paid'}, 
 {active: true , customerEmail: 'johndoe@gmail.com', status: 'open'}
]

const filter = {active: true, customerEmail: 'johndoe@gmail.com', status: 'open'}

const selectedFilterKeys = Object.keys(filter)

const filteredInvoices = invoices.filter(invoice => selectedFilterKeys.every(key => 
      filter[key] === invoice[key]
))

console.log("filteredInvoices", filteredInvoices)

答案 2 :(得分:0)

概述

作为对后端服务的API请求,筛选通常更有效,但完全可以在前端执行。我还认为您希望在事件而不是useEffect内发生这种情况。话虽这么说,这里有两个过滤选项。

选项1

为发票对象上的每个可过滤属性添加条件。

const filteredInvoices = invoices.filter((inv) => {
  const isEmailMatch = inv.customerEmail.toLowerCase() === filter.customerEmail.toLowerCase();
  const isStatusMatch = inv.status === filter.status;

  // Add other matches here.

  return isEmailMatch && isStatusMatch;
 });

选项2

这将需要从status状态中提取filter。我认为该解决方案更具可扩展性。

const [active, setActive] = useState(false); // Extracting active.
const [filter, setFilter] = useState({});

const updateFilter = () => {
  const filteredInvoices = invoices.filter((item) => {
    for (const key in filter) {
      if (item[key] === undefined || item[key] !== filter[key])
        return false;
    }
    return true;
  });
};

useEffect(() => {
  if (active) updateFilter();
}, [filter]);