【问题标题】:How to filter React state based on the value of 3 select dropdowns?如何根据 3 个选择下拉列表的值过滤 React 状态?
【发布时间】:2020-08-26 18:44:23
【问题描述】:

我有一组用户数据,可以通过 3 个按位置、部门和客户进行过滤的选择下拉列表进行过滤。

我遇到了一些边缘情况问题,如果选择了多个下拉菜单,并且我对未设置为“全部”的下拉菜单进行更改,则用户未正确过滤。

这是一组设置为“用户”状态的用户数据示例:

[
    {
        "id": 1,
        "first_name": "Sissy",
        "last_name": "Chatterton",
        "email": "schatterton0@pcworld.com",
        "bgImg": "http://dummyimage.com/500x1000.png/cc0000/ffffff",
        "profile_photo": "http://dummyimage.com/100x100.png/ff4444/ffffff",
        "title": "Statistician IV",
        "department": "Marketing",
        "city": "New York City",
        "state": "NY",
        "phone": "212-447-7193",
        "quote": "Donec ut mauris eget massa tempor convallis.",
        "quoteAuthor": "Sissy Chatterton",
        "client": "Skinder"
    },
    {
        "id": 2,
        "first_name": "Kelcie",
        "last_name": "Shildrake",
        "email": "kshildrake1@usatoday.com",
        "bgImg": "http://dummyimage.com/500x1000.png/ff4444/ffffff",
        "profile_photo": "http://dummyimage.com/100x100.png/ff4444/ffffff",
        "title": "Librarian",
        "department": "Human Resources",
        "city": "New York City",
        "state": "NY",
        "phone": "212-694-8464",
        "quote": "Aliquam non mauris. Morbi non lectus.",
        "quoteAuthor": "Kelcie Shildrake",
        "client": "Twitterworks"
    },
}

这是选择下拉菜单的标记:

const UserSearchBox = ({ handleSelectChange, handleInputChange, locations, departments, clients, locationValue, clientValue, departmentValue }) => {
    return (
        <form className="user-search">
            <input className="user-input" placeholder="Search for Peeps by name" name="userSearch" onChange={handleInputChange} />

            <div>
                <select id="locationSelect" defaultValue={locationValue} value={locationValue} onChange={handleSelectChange}>
                    <option data-filter-type="location" value="all">All</option>
                    {locations.map((x) => {
                        return(
                            <option data-filter-type="location" value={x}>{x}</option>
                        )
                    })}
                </select>

                <select id="departmentSelect" defaultValue={departmentValue} value={departmentValue} onChange={handleSelectChange}>
                    <option data-filter-type="department" value="all">All</option>
                    {departments.map((x) => {
                        return(
                            <option data-filter-type="department" value={x}>{x}</option>
                        )
                    })}
                </select>

                <select id="clientSelect" defaultValue={clientValue} value={clientValue} onChange={handleSelectChange}>
                    <option data-filter-type="client" value="all">All</option>
                    {clients.map((x) => {
                        return(
                            <option data-filter-type="client" value={x}>{x}</option>
                        )
                    })}
                </select>
            </div>


        </form>
    )
}

最后是尝试使用 onChange 处理程序过滤用户的代码:

 const [users, setUsers] = useState<User[]>([])
    const [allUsers, setAllUsers] = useState<User[]>([])
    const [locationFilter, setLocationFilter] = useState('all')
    const [clientFilter, setClientFilter] = useState('all')
    const [departmentFilter, setDepartmentFilter] = useState('all')

const handleSelectChange = (e) => {
        e.preventDefault();
        let searchTerm = e.target.value;
        let attr = e.target[e.target.selectedIndex].getAttribute('data-filter-type')

        const filterHandler = (value, userSet) => {
            setUsers(userSet.filter((x) =>
                (x.city || '').toLowerCase().includes(value.toLowerCase())
            ))
        }

        const multipleFilterHandler = () => {
            setUsers(allUsers)

            if (locationFilter !== 'all') {
                setUsers(users.filter((x) =>
                    (x.city || '').toLowerCase().includes(locationFilter.toLowerCase())
                ))
            }
            if (clientFilter !== 'all') {
                setUsers(users.filter((x) =>
                    (x.client || '').toLowerCase().includes(clientFilter.toLowerCase())
                ))
            }
            if (departmentFilter !== 'all') {
                alert("this ran")
                setUsers(users.filter((x) =>
                    (x.department || '').toLowerCase().includes(departmentFilter.toLowerCase())
                ))
            }
        }



        if (searchTerm !== "all" && users) {
            switch (attr) {
                case 'location':
                    setLocationFilter(searchTerm)
                    if (clientFilter === 'all' && departmentFilter === 'all') {
                        filterHandler(searchTerm, allUsers)
                    } else {
                        multipleFilterHandler()
                    }
                    break;
                case 'department':
                    setDepartmentFilter(searchTerm)
                    if (clientFilter === 'all' && locationFilter === 'all') {
                        filterHandler(searchTerm, allUsers)
                    } else {
                        filterHandler(searchTerm, users)
                    }
                    break;
                case 'client':
                    setClientFilter(searchTerm)
                    if (departmentFilter === 'all' && locationFilter === 'all') {
                        filterHandler(searchTerm, allUsers)
                    } else {
                        filterHandler(searchTerm, users)
                    }
                    break;
                default:
                    setUsers(allUsers)
            }
        } else {
            setUsers(allUsers)
        }
    }

因此,我遇到的一个极端情况是,如果我有两个下拉菜单并选择了一个值,并且我将这两个下拉菜单中的一个更改为不同的值,它将不起作用。

我尝试使用逻辑创建一个名为 multiplefilterhandler 的函数,它将用户重置为 allUsers(这是我们从数据库中收到的所有用户的初始数据),然后运行所有三个选择下拉菜单并根据值是否过滤不等于“全部”

这不起作用,因为它在第一个有效的 if 语句上中断。

对于这样的事情,最好的方法是什么,让一个像 multiplefilterhandler 这样的函数在 if 语句中运行?我面临的挑战是当其中一个过滤器设置为“全部”而其他过滤器未设置时该怎么办。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    我会将setUsers 从您的处理程序中拉出并放入useEffect。当任何过滤器更改时,您可以更新它。您只想调用一次,因此您可以分别应用每个过滤器并在最后设置最终数组。

      useEffect(() => {
        const filteredUsers = allUsers;
        if (locationFilter !== 'all') filteredUsers = filteredUsers.filter(x => (x.city || '').toLowerCase().includes(value.toLowerCase()))
        if (clientFilter !== 'all') filteredUsers = filteredUsers.filter(x => (x.client || '').toLowerCase().includes(value.toLowerCase()))
        if (departmentFilter !== 'all') filteredUsers = filteredUsers.filter(x => (x.department || '').toLowerCase().includes(value.toLowerCase()))
        setUsers(filteredUsers);
      }, [locationFilter, clientFilter, departmentFilter, setUsers]);
    

    然后,您可以使您的 handleFilterChange 方法变得非常简单。

      handleFilterChange = (type) => (e) => {
        const searchTerm = e.target.value;
        switch (type) {
          case 'location':
            setLocationFilter(searchTerm)
          case 'department':
            setDepartmentFilter(searchTerm)
          case 'client':
            setClientFilter(searchTerm)
        }
      }
    

    您可以在onChange 中构建您的事件函数,而不是使用数据属性。例如:

    <select 
      id="locationSelect" 
      defaultValue={locationValue} 
      value={locationValue} 
      onChange={handleFilterChange("location")}
    >
      <option value="all">All</option>
      {locations.map((x) => {
        return (
          <option value={x}>{x}</option>
        )
      })}
    </select>
    

    【讨论】:

    • 非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 2018-04-16
    • 2014-09-02
    • 2012-06-20
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多