React中使用State展示筛选列表时遇列表覆盖问题
解决React TodoList切换任务时列表被覆盖的问题
核心问题在于你维护了两个独立的状态(tasks和completedTasks),这会导致数据同步困难,切换任务时容易出现覆盖原有列表的情况。正确的思路是只维护一个完整的任务列表状态,通过筛选计算得到活跃任务和已完成任务,而非分开存储两个状态。
步骤1:简化状态定义
只保留一个存储所有任务的状态,移除单独的completedTasks状态,用useMemo实时计算分类后的任务列表:
import { useState, useEffect, useMemo } from 'react'; const LOCAL_STORAGE_KEY = 'todo_tasks'; function TodoApp() { // 仅维护一个完整的任务列表状态 const [tasks, setTasks] = useState([]); // 实时筛选活跃任务和已完成任务,useMemo避免重复计算 const activeTasks = useMemo(() => { return tasks.filter(task => task.active === true); }, [tasks]); const completedTasks = useMemo(() => { return tasks.filter(task => task.active === false); }, [tasks]); // 从LocalStorage读取完整任务数据 useEffect(() => { const storedTasks = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)); if (storedTasks) { setTasks(storedTasks); } }, []); // 任务变化时自动同步到LocalStorage useEffect(() => { localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(tasks)); }, [tasks]);
步骤2:修复新增任务逻辑
原来的addTask直接替换了整个任务数组,改为追加新任务到现有列表:
// 新增任务:确保新任务active属性为true const addTask = (newTask) => { const taskWithActive = { ...newTask, active: true, id: Date.now() }; // 加id确保唯一性 setTasks(prevTasks => [...prevTasks, taskWithActive]); };
步骤3:调整任务切换逻辑
把切换逻辑放到父组件,直接更新完整任务列表,无需手动拆分数据:
// 切换任务的active状态 const toggleTaskActive = (taskId) => { setTasks(prevTasks => prevTasks.map(task => { if (task.id === taskId) { return { ...task, active: !task.active }; } return task; }) ); };
步骤4:修改List组件调用方式
给两个列表分别传入对应分类的任务和切换函数即可:
return ( <div> <h2>当前任务</h2> <List tasks={activeTasks} toggleTask={toggleTaskActive} /> <h2>已完成任务</h2> <List tasks={completedTasks} toggleTask={toggleTaskActive} /> </div> ); }
步骤5:简化List组件
List组件只负责渲染任务和触发切换操作:
function List({ tasks, toggleTask }) { return ( <ul> {tasks.map(task => ( <li key={task.id}> <input type="checkbox" checked={!task.active} // 已完成任务对应复选框勾选状态 onChange={() => toggleTask(task.id)} /> <span>{task.text}</span> </li> ))} </ul> ); }
为什么这样能解决问题?
- 单一数据源:所有任务都存在
tasks状态中,避免了两个状态不同步的问题。 - 实时计算分类:
activeTasks和completedTasks通过useMemo从完整列表实时筛选,数据始终最新。 - 自动持久化:通过
useEffect监听tasks变化,自动同步到LocalStorage,无需在每个操作里手动调用存储方法。
这样修改后,切换任务时只会更新对应任务的active属性,两个列表会自动重新渲染,不会出现原有任务被覆盖的情况。
内容的提问来源于stack exchange,提问作者theslimdev
相关产品推荐
相关产品推荐

