
本文介绍一种简洁可靠的 React 数据过滤方案:通过单一状态管理过滤条件,配合 useMemo 动态计算过滤结果,确保页面首次加载即显示全部数据("All" 默认态),同时避免冗余状态引发的渲染异常与同步风险。
本文介绍一种简洁可靠的 react 数据过滤方案:通过单一状态管理过滤条件,配合 usememo 动态计算过滤结果,确保页面首次加载即显示全部数据("all" 默认态),同时避免冗余状态引发的渲染异常与同步风险。
在构建数据筛选功能时,一个常见误区是为“已过滤的数据”单独声明一个状态(如 filterCompleted),试图缓存结果。但这种做法不仅导致状态冗余,更会引发初始渲染空白、状态不同步、逻辑耦合度高等问题——正如示例中点击按钮能正确打印日志却无法显示内容,根本原因正是 filterCompleted 初始值依赖于尚未加载完成的空数组 toDoData,造成 filterCompleted.map() 在首次渲染时报错或跳过。
✅ 正确解法是遵循 “最小必要状态”原则:只保留两个不可简化的状态:
-
toDoData:原始数据源(来自 API); -
activeFilter:当前激活的过滤类型(字符串标识,如"all"/"completed"/"not-completed")。
过滤后的数据不再作为状态存储,而是通过 useMemo 在渲染阶段派生计算:
const filteredData = React.useMemo(() => {
if (activeFilter === "all") return toDoData;
if (activeFilter === "completed") return toDoData.filter(item => item.completed);
if (activeFilter === "not-completed") return toDoData.filter(item => !item.completed);
throw new Error(`Unknown filter '${activeFilter}'`);
}, [toDoData, activeFilter]);
该 Hook 确保仅当 toDoData 加载完成或 activeFilter 变更时才重新计算,且首次渲染即以 "all" 为默认值,自然展示全部数据。
最终渲染部分直接映射 filteredData:
const renderedData = filteredData.map((item) => (
<data key="{item.id}" userid="{item.userId}" title="{item.title}" completed="{item.completed" :></data>
));
按钮事件只需更新 activeFilter:
<button onclick="{()"> setActiveFilter("completed")}>Completed</button>
<button onclick="{()"> setActiveFilter("not-completed")}>Not Completed</button>
<button onclick="{()"> setActiveFilter("all")}>All</button>
⚠️ 注意事项:
- 避免将派生数据(如过滤结果)设为
useState,否则需手动维护与源数据的一致性,极易出错; -
useMemo的依赖数组[toDoData, activeFilter]必须完整准确,缺一不可; - 若未来扩展过滤类型(如按
userId搜索),只需新增分支逻辑与对应按钮,无需修改状态结构; - 所有副作用(如 API 刷新)仅操作
toDoData,其余视图自动响应更新,大幅降低维护成本。
这一模式体现了 React 的核心思想:状态越少、越纯粹,应用就越健壮、越可预测。











