React Todo应用报错:todo未定义问题求助
问题背景
开发React Todo应用时拆分了多个组件,运行时应用无法正常显示,控制台始终在footer.js第15行抛出「Uncaught TypeError: todo is undefined」错误。已通过useState维护todo数组并作为props传递给TodoCounter组件,尝试过重命名props、调整组件调用位置,但问题未解决。
相关代码
app.js
import React, { useState } from 'react'; import './App.css'; import InputTodos from './input.js'; import ListTodos from './list.js'; import TodoCounter from './footer.js'; import ClearButton from './clearbutton.js'; function App() { // 创建todo状态 const [todo, setTodo] = useState([]); return ( <div className="App"> <div className="container"> <div className="header"> <InputTodos todo={todo} setTodo={setTodo} /> </div> <div className="containerMid"> <ListTodos todo={todo} /> </div> <div className="footer"> <TodoCounter todo={todo} /> </div> <div className="buttonCleardiv"> <ClearButton todo={todo} setTodo={setTodo} /> </div> </div> </div> ); } export default App;
footer.js
import React, { useEffect, useState } from 'react'; import './App.css'; function TodoCounter(props) { const { todo } = props; const [completed, setCompleted] = useState(0); const [notCompleted, setNotCompleted] = useState(0); // 统计已完成和未完成的todo数量 function counttodos(props) { const { todo } = props; return { completed: todo.filter((todo) => todo.isChecked).length, notCompleted: todo.filter((todo) => !todo.isChecked).length, }; } useEffect(() => { const { completed, notcompleted } = counttodos(todo); setCompleted(completed); setNotCompleted(notcompleted); }, [todo]); return ( <div> <p>Completed: {completed}</p> <p>Not Completed: {notCompleted}</p> <p>Todos: {todo.length} </p> </div> ); } export default TodoCounter;
错误原因分析
问题出在counttodos函数的调用和定义不匹配:
counttodos函数定义时期望接收一个包含todo属性的对象,并通过const { todo } = props;解构获取todo数组。- 但在
useEffect中调用该函数时,直接传入了todo数组本身,而非包含todo的对象。此时counttodos里的props是数组,解构props.todo自然会得到undefined,后续执行todo.filter时就会抛出类型错误。
另外,原代码中解构的notcompleted拼写错误,与函数返回的notCompleted不一致,会导致未完成数量始终为0;同时filter回调参数名和外部todo数组重名,容易造成混淆。
修复方案
方案一:调整函数调用方式
在useEffect中调用counttodos时,把todo数组包装成对象传入,同时修正拼写错误:
useEffect(() => { const { completed, notCompleted } = counttodos({ todo }); setCompleted(completed); setNotCompleted(notCompleted); }, [todo]);
方案二:简化函数参数定义
直接让counttodos接收todo数组作为参数,避免解构对象,同时修改回调参数名避免重名:
// 修改counttodos函数 function counttodos(todo) { return { completed: todo.filter((item) => item.isChecked).length, notCompleted: todo.filter((item) => !item.isChecked).length, }; } // 对应修改useEffect调用 useEffect(() => { const { completed, notCompleted } = counttodos(todo); setCompleted(completed); setNotCompleted(notCompleted); }, [todo]);
额外优化建议
可以省去useEffect和额外的state,直接基于todo数组计算统计值,代码更简洁高效:
function TodoCounter(props) { const { todo } = props; const completed = todo.filter(item => item.isChecked).length; const notCompleted = todo.length - completed; return ( <div> <p>Completed: {completed}</p> <p>Not Completed: {notCompleted}</p> <p>Todos: {todo.length} </p> </div> ); }
内容的提问来源于stack exchange,提问作者Davidino
相关产品推荐
相关产品推荐

