Javascript 按设置的列表价格范围和其他选项筛选对象数组

Javascript 按设置的列表价格范围和其他选项筛选对象数组,javascript,reactjs,filtering,Javascript,Reactjs,Filtering,我有一个具有以下结构的对象数组: { “id”:“3c97d11f-3feb-5af5-8092-b3f5c4a8257d”, “名称”:“褶边条纹有机棉衬衫”, “价格”:215, “referralUrl”:“link.com”, “imageUrl”:“//images.url”, “图像高度”:3000, “图像宽度”:2000, “imageSrcSet”:[…], “imageSrcSetSizes”:[(最大宽度:667px)100vw,667px”], “已创建”:“2020-1

我有一个具有以下结构的对象数组:

{
“id”:“3c97d11f-3feb-5af5-8092-b3f5c4a8257d”,
“名称”:“褶边条纹有机棉衬衫”,
“价格”:215,
“referralUrl”:“link.com”,
“imageUrl”:“//images.url”,
“图像高度”:3000,
“图像宽度”:2000,
“imageSrcSet”:[…],
“imageSrcSetSizes”:[(最大宽度:667px)100vw,667px”],
“已创建”:“2020-11-01T22:37:17.927Z”,
“标签”:[],
“类别”:[“衣服”],
“颜色”:[“中性色”],
“负责任地”:[]
},
{
...,
价格:1000,
...
}
我有一个过滤器,它通过我设置的所有过滤器循环,如下所示:

const multiFilter = (item, condition) => {
  const filterKeys = Object.keys(condition)
  return item.filter((eachObj) => {
    return filterKeys.every((eachKey) => {
      if (!condition[eachKey].length) {
        return true // passing an empty filter means that filter is ignored.
      }

      return condition[eachKey]
        .toString()
        .toLowerCase()
        .includes(eachObj[eachKey].toString().toLowerCase())
    })
  })
}
现在,当我的filters对象是单值和数组时,这一点非常有效,但当我尝试选择价格过滤器时,
条件[eachKey]
返回为未定义,然后页面失败。我确信这与我如何为价格设置表单字段值以及如何将它们推送到过滤器状态对象有关

下面是我如何构建价格过滤器HTML的:

<form>
            <label>
              <input
                type="radio"
                name="prices"
                value='{"rangeFrom":0,"rangeTo":50}'
                onChange={(e) => handleChange(e)}
              />
              Up to &pound;50
            </label>

            <label>
              <input
                type="radio"
                name="prices"
                value='{"rangeFrom":50,"rangeTo":100}'
                onChange={(e) => handleChange(e)}
              />
              &pound;50 - &pound;100
            </label>

            <label>
              <input
                type="radio"
                name="prices"
                value='{"rangeFrom":100,"rangeTo":250}'
                onChange={(e) => handleChange(e)}
              />
              &pound;100 - &pound;250
            </label>

            <label>
              <input
                type="radio"
                name="prices"
                value='{"rangeFrom":250,"rangeTo":500}'
                onChange={(e) => handleChange(e)}
              />
              &pound;250 - &pound;500
            </label>

            <label>
              <input
                type="radio"
                name="prices"
                value='{"rangeFrom":500}'
                onChange={(e) => handleChange(e)}
              />
              &pound;500+
            </label>

            <label>
              <input
                type="radio"
                name="prices"
                value="all"
                onChange={(e) => handleChange(e)}
              />
              All
            </label>
          </form>
它生成的对象类似于:

{
    categories: ['cat1', 'cat'],
    colours: ['blue', 'red, 'green'],
    other: ['thing', 'foo'],
    price: ['{"rangeFrom":250,"rangeTo":500}']
}
我不知道如何修改multiFilter函数以接受价格数组,并让它查看
rangeFrom
rangeTo
值,并按所选范围过滤产品价格

有什么想法吗


谢谢

您可以使用
JSON.parse
尝试将筛选值转换为对象,例如:

const [filters, setFilters] = useState(FILTERS);

const filteredItems = useMemo(() => {
  const activeFilters = filters.filter(f => f.isActive);

  return activeFilters.length > 0
    ? ITEMS.filter(item => activeFilters.every(f => f.apply(item)))
    : ITEMS;
}, [filters]);
constmultifilter=(项目、条件)=>{
const filterKeys=Object.keys(条件);
返回items.filter(item=>filterKeys.every(filterKey=>{
常量filterValues=条件[filterKey];
if(!filterValues.length){
return true//传递空筛选器意味着忽略筛选器。
}
const itemValue=项[filterKey];
试一试{
//处理对象过滤器值
返回filterValues
.map(JSON.parse)
.some({rangeFrom,rangeTo})=>itemValue>=rangeFrom&&itemValue
filterValue.toString().toLowerCase()==
itemValue.toString().toLowerCase()
);
}
})
}
不过,这种方法的缺点是有点“脆弱”——如果您想引入一种新型过滤器来检查
创建的日期是否在一个范围内,会发生什么情况

<label>
    <input
    type="radio"
    name="created"
    value='{"minDate":"2020-01-01","maxDate":"2021-01-01"}'
    onChange={handleChange}
    />
    Created in 2020
</label>
您也可以有不同类型的过滤器,例如,
dateFilter
,或
nameFilter
,只要确保它们都有相同的接口即可

现在您已经有了过滤器,您可以创建一个组件来呈现过滤器,并响应更改-下面是一个基本过滤器,显示标签和“应用”/“删除”按钮:


-我很快就把它组合在一起了,所以不要评判我糟糕的风格谢谢你的回复@gerrod。我已经尝试实施你的解决方案,但在选择价格过滤器时似乎没有返回任何结果。你有什么建议可以让实施类似的过滤系统变得不那么脆弱吗?我目前看到一些奇怪的现象结果与原始筛选代码一起出现,其中一些项目在不应该返回的情况下返回,因此我正在重新考虑我的整体方法,因此非常感谢您对此的想法。@thomasbritton-使用数据驱动的方法进行筛选可能更好-检查我的更新答案感谢更新。它适用于大部分情况下,但是按照生成过滤器的新样式,当我想要选择多个不同的过滤器时,它会下降,例如,我想要返回所有分类为“礼物”和“鞋子”以及“价格”的物品,可能还有一些其他过滤器,例如“颜色”"等等。我试图为特定的过滤器类型更改
apply
函数,但无法使它们很好地结合起来,结果只过滤到与API返回的数据完全匹配的特定产品。有什么想法可以实现这一点吗?这一切都取决于如何编写过滤器集合-在我的代码中andbox我做得很幼稚(使用了一系列的活动过滤器),但您可以按自己喜欢的方式对过滤器进行分类。如果您提供一个CodeSandbox演示来显示问题,这可能会有所帮助?我已将您的codesanbox@gerrod分叉,并将数据和显示问题的“我要去的地方”添加到其中。链接是:“'categories'键以数组的形式出现,但我已将其更改为字符串。”我一直在努力,看看我是否能把它整合在一起。如果可能的话,我认为保持它作为一个数组会更好。最终,我试图达到一个分面过滤系统,你通常会在电子商务网站上找到。
const Filter = ({ filter, onChange }) => {
  const handleChange = () => onChange(filter, !filter.isActive);
  const buttonText = filter.isActive ? "Remove" : "Apply";
  const className = `filter ${filter.isActive ? "active" : "inactive"}`;

  return (
    <div className={className}>
      <span>{filter.label}</span>
      <input type="button" onClick={handleChange} value={buttonText} />
    </div>
  );
};
const [filters, setFilters] = useState(FILTERS);

const filteredItems = useMemo(() => {
  const activeFilters = filters.filter(f => f.isActive);

  return activeFilters.length > 0
    ? ITEMS.filter(item => activeFilters.every(f => f.apply(item)))
    : ITEMS;
}, [filters]);