使用 React 过滤数组:多条件筛选特定元素
在前端开发中,我们经常需要根据用户的输入或者预设的规则,从一组数据中筛选出符合要求的元素。React 作为主流的前端框架,提供了灵活的状态管理和渲染机制,配合 JavaScript 原生的数组方法,可以很方便地实现多条件筛选功能。本文将通过一个实际案例,介绍如何在 React 中实现数组的多条件过滤。
核心思路
实现多条件筛选的核心逻辑可以分为三步:
- 维护原始数据数组和筛选条件状态,筛选条件通常会绑定到表单元素上,由用户操作触发更新
- 使用
useEffect或者直接在渲染阶段,根据当前的筛选条件对原始数组进行过滤处理 - 将过滤后的结果渲染到页面上,同时保证原始数据不被修改,方便后续调整筛选条件时重新计算
这里我们使用 JavaScript 的 Array.filter 方法作为过滤的核心,它会返回一个新数组,包含所有通过测试函数的元素,不会修改原数组,非常适合这种场景。
完整代码示例
下面的示例模拟了一个商品列表的筛选场景,支持按商品名称关键词、价格区间、商品分类三个条件进行筛选,所有筛选条件可以组合使用。
import { useState, useMemo } from 'react';
// 原始商品数据
const goodsList = [
{ id: 1, name: '无线蓝牙耳机', price: 299, category: '数码' },
{ id: 2, name: '纯棉短袖T恤', price: 89, category: '服饰' },
{ id: 3, name: '机械键盘', price: 459, category: '数码' },
{ id: 4, name: '运动休闲裤', price: 159, category: '服饰' },
{ id: 5, name: '便携充电宝', price: 129, category: '数码' },
{ id: 6, name: '帆布鞋', price: 199, category: '鞋靴' },
];
export default function GoodsFilter() {
// 筛选条件状态
const [keyword, setKeyword] = useState('');
const [minPrice, setMinPrice] = useState('');
const [maxPrice, setMaxPrice] = useState('');
const [selectedCategory, setSelectedCategory] = useState('全部');
// 使用 useMemo 缓存过滤结果,避免不必要的重复计算
const filteredGoods = useMemo(() => {
return goodsList.filter(item => {
// 关键词筛选:名称包含输入的关键词(不区分大小写)
const matchKeyword = keyword === '' || item.name.toLowerCase().includes(keyword.toLowerCase());
// 价格区间筛选:如果输入了最低价则判断商品价 >= 最低价,输入了最高价则判断商品价 <= 最高价
const matchMinPrice = minPrice === '' || item.price >= Number(minPrice);
const matchMaxPrice = maxPrice === '' || item.price <= Number(maxPrice);
// 分类筛选:选择全部则不过滤,否则匹配对应分类
const matchCategory = selectedCategory === '全部' || item.category === selectedCategory;
// 所有条件都满足才返回该元素
return matchKeyword && matchMinPrice && matchMaxPrice && matchCategory;
});
}, [keyword, minPrice, maxPrice, selectedCategory]);
// 获取所有不重复的分类选项
const categoryOptions = ['全部', ...new Set(goodsList.map(item => item.category))];
return (
<div className="goods-filter-container">
<h2>商品筛选</h2>
<div className="filter-form">
<div className="filter-item">
<label>商品名称:</label>
<input
type="text"
value={keyword}
onChange={(e) => setKeyword(e.target.value)}
placeholder="输入关键词搜索"
/>
</div>
<div className="filter-item">
<label>价格区间:</label>
<input
type="number"
value={minPrice}
onChange={(e) => setMinPrice(e.target.value)}
placeholder="最低价"
min="0"
/>
<span> - </span>
<input
type="number"
value={maxPrice}
onChange={(e) => setMaxPrice(e.target.value)}
placeholder="最高价"
min="0"
/>
</div>
<div className="filter-item">
<label>商品分类:</label>
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
>
{categoryOptions.map(option => (
<option key={option} value={option}>{option}</option>
))}
</select>
</div>
</div>
<div className="goods-list">
<h3>筛选结果(共 {filteredGoods.length} 件)</h3>
{filteredGoods.length === 0 ? (
<p>没有找到符合条件的商品</p>
) : (
<ul>
{filteredGoods.map(item => (
<li key={item.id} className="goods-item">
<span>名称:{item.name}</span>
<span>价格:{item.price} 元</span>
<span>分类:{item.category}</span>
</li>
))}
</ul>
)}
</div>
</div>
);
}代码解析
上述代码中,我们首先定义了原始的商品数据数组 goodsList,然后使用 useState 定义了四个筛选条件的状态:关键词 keyword、最低价 minPrice、最高价 maxPrice、选中的分类 selectedCategory。
过滤逻辑放在 useMemo 中,依赖项是四个筛选条件,只有当条件发生变化时才会重新执行过滤计算,避免每次渲染都重复处理数组,提升性能。在 filter 的回调函数中,我们分别对四个条件进行判断,只有所有条件都满足的元素才会被保留到结果数组中。
页面渲染部分,我们用了几个表单元素来绑定筛选条件:文本输入框绑定关键词,数字输入框绑定价格区间,下拉框绑定商品分类。当用户输入或者选择条件时,对应的状态更新,触发 useMemo 重新计算过滤结果,页面会自动渲染最新的筛选后的商品列表。
扩展说明
如果需要更复杂的条件组合,比如“或”逻辑的条件筛选,只需要调整 filter 回调函数中的判断逻辑,把 && 改成 || 即可。另外如果原始数据是从接口异步获取的,只需要在获取数据后存入状态,过滤逻辑不需要做太大调整,只需要把原始数据从固定的数组改成从状态中读取即可。
同时要注意,如果筛选条件很多,filter 的回调函数可能会变得冗长,这时候可以把每个条件的判断逻辑拆分成单独的函数,让代码更清晰易维护。比如把关键词匹配的 logic 写成 const checkKeyword = (item) => keyword === '' || item.name.includes(keyword),这样后续调整单个条件的逻辑时只需要修改对应的函数即可。