React待办应用新增Todo项无刷新即时显示实现方法
问题原因
你当前实现中待办列表状态todo存储在App组件内,仅在组件首次挂载时通过useEffect触发一次接口拉取。Write组件完成新待办提交后,既没有重新拉取最新全量列表,也没有将新创建的待办项同步更新到App组件的todo状态中,React检测不到状态变化自然不会重渲染页面,必须手动刷新触发首次加载逻辑才能看到新条目。
除此之外你的代码还有几个显性问题:
- App组件中渲染列表时写的是
<Task Todor={todo} />,但你定义的列表组件名为Todos,命名不匹配会直接抛出组件未定义错误 - Write组件提交成功后执行
setInputText(""),但inputText初始值是对象类型{title: ""},直接赋值为字符串会导致后续输入时展开操作报错 - Write组件中
setInputText(inputText)是无效冗余代码,没有实际作用 - 输入框没有绑定value属性,状态重置时会出现视图和数据不同步的问题
修复方案
二选一即可,小数据量场景推荐用方案1,逻辑简单不容易出问题;待办项多、追求性能用方案2。
方案1:新增成功后重新拉取全量列表
核心逻辑是把App组件内的拉取列表方法透传给Write组件,新增成功后直接调用触发列表刷新。
首先修改App组件:
function App() { const [todo, setTodo] = useState([]); async function getTodo() { try { const todoRes = await axios.get("http://localhost:5000/api/todos"); setTodo(todoRes.data); } catch (error) { console.log("获取待办列表失败", error); } } useEffect(() => { getTodo(); }, []); return ( <div className="App"> <h1>My Todo List</h1> <h2>My Todo List</h2> {/* 修正组件名错误,将刷新方法透传给Write组件 */} <Todos Todor={todo} /> <Write onAddSuccess={getTodo} /> </div> ); } export default App;
再修改Write组件:
export default function Write({ onAddSuccess }) { const [inputText, setInputText] = useState({ title: "" }); function handleChange(e) { setInputText({ ...inputText, [e.target.name]: e.target.value, }); } async function addItem(e) { e.preventDefault(); // 拦截空内容提交 if (!inputText.title.trim()) return try { await axios.post("http://localhost:5000/api/todos", inputText); // 重置输入框时保持和初始值一致的对象格式 setInputText({title: ""}); // 调用父组件方法刷新列表 onAddSuccess?.(); } catch (error) { console.log("新增待办失败", error); } } return ( <div className="container"> <div className="form"> {/* 绑定value属性保证状态和视图同步 */} <input onChange={handleChange} type="text" name="title" value={inputText.title} /> <button onClick={addItem}> <span>Add</span> </button> </div> </div> ); }
方案2:新增成功后直接追加新条目到本地状态
不需要二次请求拉取全量列表,性能更好,注意需要确保post接口返回新创建的完整待办对象。
修改App组件:
function App() { const [todo, setTodo] = useState([]); async function getTodo() { try { const todoRes = await axios.get("http://localhost:5000/api/todos"); setTodo(todoRes.data); } catch (error) { console.log("获取待办列表失败", error); } } useEffect(() => { getTodo(); }, []); return ( <div className="App"> <h1>My Todo List</h1> <h2>My Todo List</h2> <Todos Todor={todo} /> {/* 把状态更新方法透传给Write */} <Write setTodoList={setTodo} /> </div> ); } export default App;
修改Write组件:
export default function Write({ setTodoList }) { const [inputText, setInputText] = useState({ title: "" }); function handleChange(e) { setInputText({ ...inputText, [e.target.name]: e.target.value, }); } async function addItem(e) { e.preventDefault(); if (!inputText.title.trim()) return try { const res = await axios.post("http://localhost:5000/api/todos", inputText); // 将接口返回的新待办追加到列表头部,需要新条目放尾部就改成[...prev, res.data] setTodoList(prev => [res.data, ...prev]); setInputText({title: ""}); } catch (error) { console.log("新增待办失败", error); } } return ( <div className="container"> <div className="form"> <input onChange={handleChange} type="text" name="title" value={inputText.title} /> <button onClick={addItem}> <span>Add</span> </button> </div> </div> ); }
注意:如果你的post接口没有返回新创建的待办完整字段(比如后端生成的id、创建时间等),不要用方案2,优先选方案1避免后续操作因为字段缺失报错。
内容的提问来源于stack exchange,提问作者The Tech Guy
相关产品推荐
相关产品推荐

