React中如何将已完成Todo移至列表末尾,取消完成时恢复原位置?
React Todo 任务排序解决方案
要实现「标记完成移至底部、取消完成恢复原位置」的功能,核心是给每个任务记录原始创建顺序,渲染时按「未完成任务按原始顺序排列 + 已完成任务按原始顺序排列」的规则组合列表。
1. 完善App组件的状态与逻辑
先修正你App组件里的拼写错误(Headers→Header),并添加状态管理和核心处理函数:
import './App.css'; import Header from './components/Header'; import Form from './components/Form'; import List from './components/List'; import { useState } from 'react'; function App() { // 每个todo包含:唯一id、任务文本、完成状态、原始创建顺序 const [todos, setTodos] = useState([]); let nextOrder = todos.length + 1; // 添加新任务 const addTodo = (text) => { setTodos([ ...todos, { id: Date.now(), text, done: false, order: nextOrder++ } ]); }; // 切换任务完成状态 const toggleTodo = (id) => { setTodos(todos.map(todo => todo.id === id ? {...todo, done: !todo.done} : todo )); }; // 排序逻辑:未完成任务按原始顺序排,已完成任务按原始顺序排并放在后面 const sortedTodos = [ ...todos.filter(todo => !todo.done).sort((a, b) => a.order - b.order), ...todos.filter(todo => todo.done).sort((a, b) => a.order - b.order) ]; return ( <div className="Todo App"> <Header /> <Form addTodo={addTodo} /> <List todos={sortedTodos} toggleTodo={toggleTodo} /> </div> ); } export default App;
2. 实现List组件(渲染任务列表)
在./components/List.jsx里编写列表渲染逻辑,接收排序后的todos和切换状态的函数:
const List = ({ todos, toggleTodo }) => { return ( <ul className="todo-list"> {todos.map(todo => ( <li key={todo.id} className={todo.done ? 'todo-item done' : 'todo-item'} onClick={() => toggleTodo(todo.id)} > {todo.text} </li> ))} </ul> ); }; export default List;
3. 简单实现Form组件(添加任务)
在./components/Form.jsx里实现添加任务的表单:
import { useState } from 'react'; const Form = ({ addTodo }) => { const [inputText, setInputText] = useState(''); const handleSubmit = (e) => { e.preventDefault(); if (inputText.trim()) { addTodo(inputText.trim()); setInputText(''); } }; return ( <form onSubmit={handleSubmit} className="todo-form"> <input type="text" value={inputText} onChange={(e) => setInputText(e.target.value)} placeholder="添加新任务..." /> <button type="submit">添加</button> </form> ); }; export default Form;
4. 样式辅助(可选)
在App.css里添加简单样式区分完成状态:
.todo-item { padding: 8px; margin: 4px 0; border: 1px solid #eee; cursor: pointer; } .todo-item.done { text-decoration: line-through; color: #999; }
核心原理说明
- 每个任务的
order属性记录了它被创建的先后顺序,不会随完成状态改变 - 渲染时先筛选出未完成任务,按
order升序排列(保持原始顺序);再筛选已完成任务,同样按order升序排列(保持它们完成前的顺序),最后把两组拼在一起,就实现了「完成任务移到底部,取消完成回到原位置」的效果
内容的提问来源于stack exchange,提问作者santa_cloudy
相关产品推荐
相关产品推荐

