You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Todo列表状态修改与多条件筛选功能异常修复咨询

修复你的React Todo列表筛选与状态更新问题

我看了你的代码,问题出在你直接把展示用的 todo 列表当成了数据源来修改,导致多次筛选后原始数据丢失,而且状态更新也用了初始的固定数组,自然会出问题。咱们一步步来修复:

问题根源拆解

  • 筛选操作破坏了原始数据:你点击筛选按钮时,直接把myTodo替换成了筛选后的子集(比如点"Filter By done"后,myTodo就只剩已完成的项了),再点其他筛选时,只能从这个子集里继续过滤,最后就没数据了。
  • 状态更新用了固定初始值:changeStatus里用的是一开始定义的todos常量,而不是当前状态里的 todo 列表,这会导致你修改状态后,新的todo状态不会被保存到后续的操作里。

修复方案

咱们把完整数据源和展示用的筛选后列表分开:

  • 用一个状态保存所有的todo数据(始终是完整的列表)
  • 用另一个状态跟踪当前的筛选条件
  • 展示的列表是根据完整数据源和筛选条件实时计算出来的

修复后的完整代码

import { useState } from "react"; 
import "./styles.css"; 

export default function App() { 
  // 保存完整的todo数据源,所有修改都基于这个状态
  const [allTodos, setAllTodos] = useState([ 
    { title: 'test', id: 1, done: false }, 
    { title: 'test2', id: 2, done: true }, 
  ]); 
  // 跟踪当前的筛选条件,初始为全部
  const [currentFilter, setCurrentFilter] = useState('all');

  // 修改todo状态:基于完整的allTodos创建副本,更新对应项的done值
  const changeStatus = (e, id) => { 
    const newTodos = allTodos.map(todo => { 
      if(todo.id === id) { 
        // 注意:option的value是字符串,直接转成布尔值判断
        return { ...todo, done: e.target.value === 'false' }; 
      } 
      return todo; 
    }); 
    setAllTodos(newTodos); 
  }; 

  // 筛选函数只需要修改筛选条件状态即可
  const filterAll = () => setCurrentFilter('all'); 
  const filterDone = () => setCurrentFilter('done'); 
  const filterActive = () => setCurrentFilter('active'); 

  // 根据当前筛选条件,从完整数据源中过滤出要展示的todo
  const displayedTodos = allTodos.filter(todo => {
    if(currentFilter === 'done') return todo.done;
    if(currentFilter === 'active') return !todo.done;
    return true; // 展示全部的情况
  });

  return ( 
    <div className="App"> 
      <button onClick={filterAll}>Filter By all</button> 
      <button onClick={filterDone}>Filter By done</button> 
      <button onClick={filterActive}>Filter By active</button> 
      { displayedTodos.map(todo => ( 
        <div key={todo.id}> {/* 给列表项加key,符合React渲染规范 */}
          {todo.title} 
          <select onChange={(e) => changeStatus(e, todo.id)} name="status"> 
            <option hidden>status</option> 
            <option value='false'>Done</option> 
            <option value='true'>Active</option> 
          </select> 
          {todo.done ? 'done' : 'active'} 
        </div> 
      )) } 
    </div> 
  ); 
}

关键修改说明

  1. 拆分数据源与展示列表:用allTodos保存完整的todo数据,永远不直接修改它的长度,只修改其中项的状态;displayedTodos是实时计算的筛选结果,不会破坏原始数据。
  2. 筛选逻辑简化:筛选按钮不再直接修改todo列表,只更新currentFilter状态,React会自动重新计算displayedTodos。
  3. 状态更新修正:changeStatus现在基于allTodos状态来创建副本,保证修改的是最新的todo数据。
  4. 添加列表key:给列表项加上key={todo.id},符合React的列表渲染规范,避免控制台警告。

这样修改后,不管你怎么切换筛选,都是基于完整的todo列表来过滤,修改todo状态后也会自动更新对应筛选下的展示结果,完全解决了你遇到的问题~

内容的提问来源于stack exchange,提问作者Asking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 21:27:36