【问题标题】:Filter on a list with headings and keep heading of filtered item(s)过滤带有标题的列表并保留过滤项目的标题
【发布时间】:2020-06-30 13:29:49
【问题描述】:

我有一个数据集,其中每个对象都有一个标题和一个包含多个值的项目数组。我需要能够在保持标题的同时过滤项目。下面的过滤器组件在没有标题的情况下工作。我想要的数据输出是这样的:

如果我过滤“ap...”

输出:

水果

苹果

const FilterList = () => {
  const [searchTerm, setSearchTerm] = useState("")
  const [searchResults, setSearchResults] = useState([])

  const data = [
    {
      heading: 'fruits',
      items: [
        { item: 'apple' },
        { item: 'orange' },      
        { item: 'peach' }
      ]
    },
    {
      heading: 'veggies'
      items: [
        { item: 'carrot' },
        { item: 'broccoli' },      
        { item: 'spinach' }, 
      ]
    }
  ]

  const handleChange = e => {
    setSearchTerm(e.target.value)
  }

  useEffect(() => {
    let results = []
    if (data && Object.prototype.hasOwnProperty.call(data[0], "heading")) {
      data.forEach(item => {
        results = item.values.filter(value =>
          value.value.toLowerCase().includes(searchTerm)
        )
      })
      setSearchResults(results)
    }
  }, [searchTerm])

  return (
    <div>
      <input
        type="text"
        placeholder={'placeholder}
        value={searchTerm}
        onChange={handleChange}
      />
      <Typography>
        <strong>{heading}</strong>
      </Typography>
      <List>
        {searchResults.map((value, i) => (
          <ListItem key={i}>
            {value.value}
          </ListItem>
        ))}
      </List>
    </div>
  )
}

【问题讨论】:

  • 您还想要多个标题吗?例如,如果有一个以ap 开头的蔬菜......你想要那个标题?
  • @iamaatoh 是的 - 两个标题都将显示在各自的过滤项目上方

标签: javascript arrays reactjs filter


【解决方案1】:

修改useEffect

useEffect(() => {
    console.log("changed");
    const newSearchResults = data.map(value => ({
      heading: value.heading,
      items: value.items.filter(item => item.item.includes(searchTerm))
    }));
    setSearchResults(newSearchResults);
  }, [searchTerm]);

将您的 return 更改为:

return (
    <div>
      <input
        type="text"
        placeholder={"placeholder"}
        value={searchTerm}
        onChange={handleChange}
      />
      <div>
        {searchResults.map(value => {
          if (value.items.length !== 0) {
            return (
              <>
                <Typography>
                  <strong>{value.heading}</strong>
                </Typography>
                <List>
                  {value.items.map((item, i) => (
                    <ListItem key={i}>{item.item}</ListItem>
                  ))}
                </List>
              </>
            );
          }
        })}
      </div>
    </div>

【讨论】:

    【解决方案2】:

    const data = [{heading:'fruits',items:[{item:'apple'},{item:'orange'},{item:'peach'}]},{heading:'veggies',items:[{item:'carrot'},{item:'broccoli'},{item:'spinach'},{item: 'peach'}]}]
    
    const filterData = (data, val) => {
      const result = []
      data.forEach(obj => {
        let r = obj.items.filter(item => item.item.includes(val))
        if(r.length > 0) {
          result.push({
            ...obj,
            items: r
          })
        }
      })
      return result
    }
    
    console.log(filterData(data, "ap"))
    console.log(filterData(data, "pe"))

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      创建了一个沙盒:https://codesandbox.io/s/strange-robinson-tvl7d?file=/src/App.js

      说明

      本质上需要做两处改变:

      • 需要重组您的searchResults,使其具有与data 相同的结构,即headingitems。除了推送找到的项目,我们还在searchResults 数组中指定了相应的heading
      // new filtering function
        useEffect(() => {
          const results = [];
          data.forEach(cate => {
            const { heading, items } = cate;
      
            // remains as is
            const filterdItems = items.filter(item =>
              item.item.toLowerCase().includes(searchTerm)
            );
      
            // only if filtered items are found
            // add BOTH category & filtered items to results
            if (filterdItems.length) {
              results.push({
                heading,
                items: filterdItems
              });
            }
          });
      
          setSearchResults(results);
        }, [searchTerm]);
      
      • 然后,更新 render 块以循环遍历类别数组,然后遍历每个类别中的项目
      // updated render
      {
       searchResults.map((resultCate, i) => {
        return (
          <div>
            <strong>{resultCate.heading}</strong>
            {resultCate.items.map((item, idx) => (
              <div key={idx}>{item.item}</div>
            ))}
          </div>
        );
      })}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-08
        • 2017-08-07
        • 1970-01-01
        • 1970-01-01
        • 2016-03-21
        • 1970-01-01
        相关资源
        最近更新 更多