React实现点击过滤数组并默认显示全部数据的问题
问题分析与解决方案
问题根源
- 当前
data变量始终基于原始的toDoData生成,点击按钮更新filterCompleted状态后,data不会重新计算,页面内容自然不会变化。 - 若改成
filterCompleted.map,初始时filterCompleted是空数组,且API请求完成后仅更新了toDoData,未同步更新filterCompleted,导致初始页面无内容。
解决方案一:同步过滤状态的初始数据
修改App.jsx,让filterCompleted在API请求完成后同步获取全部数据,并且始终基于filterCompleted生成页面内容:
import React from "react"; import Data from "../components/Data"; import "./App.css"; export default function App() { const [toDoData, setToDoData] = React.useState([]); const [filterCompleted, setFilterCompleted] = React.useState([]); React.useEffect(function () { fetch(`https://jsonplaceholder.typicode.com/todos`) .then((res) => res.json()) .then((data) => { setToDoData(data); // 初始加载时把全部数据赋值给filterCompleted setFilterCompleted(data); }); }, []); // 基于filterCompleted生成展示内容 const data = filterCompleted.map((item) => { return ( <Data key={item.id} userId={item.userId} title={item.title} completed={item.completed ? "true" : "false"} /> ); }); function handleCompleted() { const completedArray = toDoData.filter((data) => data.completed); setFilterCompleted(completedArray); } function handleNotCompleted() { const notCompletedArray = toDoData.filter((data) => !data.completed); setFilterCompleted(notCompletedArray); } function handleAll() { setFilterCompleted(toDoData); } return ( <div> <div className="btn"> <button onClick={handleCompleted}>Completed</button> <button onClick={handleNotCompleted}>Not Completed</button> <button onClick={handleAll}>All</button> </div> <div className="data">{data}</div> </div> ); }
解决方案二:使用过滤条件状态(更简洁推荐)
去掉filterCompleted状态,改用一个记录当前过滤类型的状态,根据类型实时过滤原始数据:
import React from "react"; import Data from "../components/Data"; import "./App.css"; export default function App() { const [toDoData, setToDoData] = React.useState([]); // 记录当前过滤类型:'all' | 'completed' | 'notCompleted' const [currentFilter, setCurrentFilter] = React.useState('all'); React.useEffect(function () { fetch(`https://jsonplaceholder.typicode.com/todos`) .then((res) => res.json()) .then((data) => { setToDoData(data); }); }, []); // 根据当前过滤条件实时过滤数据 const filteredData = toDoData.filter(item => { if (currentFilter === 'completed') return item.completed; if (currentFilter === 'notCompleted') return !item.completed; return true; // all的情况返回所有数据 }); const data = filteredData.map((item) => { return ( <Data key={item.id} userId={item.userId} title={item.title} completed={item.completed ? "true" : "false"} /> ); }); return ( <div> <div className="btn"> <button onClick={() => setCurrentFilter('completed')}>Completed</button> <button onClick={() => setCurrentFilter('notCompleted')}>Not Completed</button> <button onClick={() => setCurrentFilter('all')}>All</button> </div> <div className="data">{data}</div> </div> ); }
关键修改点
- 方案一中,在API请求完成后同步更新
filterCompleted,确保初始显示全部数据;同时让页面内容基于filterCompleted生成,状态变化时自动更新页面。 - 方案二中,通过
currentFilter状态控制过滤逻辑,无需维护两份数据,代码更简洁,也避免了状态不同步的问题。
内容的提问来源于stack exchange,提问作者Nguyen Thanh Hien
相关产品推荐
相关产品推荐

