React待办应用开发出现.push is not a function报错排查
问题描述
开发React待办事项应用时,已实现输入框内容与todo状态的绑定,点击新增按钮时希望将输入内容存入todos数组状态,实际运行时第一次点击可正常添加内容,第二次点击抛出错误:
Uncaught TypeError: todos.push is not a function
初始实现的核心代码如下:
// 输入状态绑定 const [todo, setTodo] = useState(""); const [todos, setTodos] = useState([]); const handleChange = (e) => { setTodo(e.target.value); } // 新增按钮逻辑 const handleClick = () => { setTodos(todos.push(todo)); console.log(todos); }
错误原因
问题出在setTodos(todos.push(todo))这行代码,核心原因有两个:
Array.push()的返回值是数组修改后的长度(数字类型),不是修改后的数组本身。第一次点击时,初始todos是空数组,执行push后返回值是数字1,调用setTodos(1)会把todos状态从数组替换成数字1。第二次点击时尝试对数字类型的值调用push方法,自然会抛出"push is not a function"的错误。- React状态遵循不可变原则,直接调用
push修改原todos数组本身,属于直接修改状态,即使返回值正确,也可能引发组件不重新渲染的问题。
修复方案
修改新增逻辑,不要直接修改原数组,而是创建新的数组副本传入状态更新函数,推荐使用函数式更新避免闭包导致的状态陈旧问题:
const handleClick = () => { // 函数式更新:prevTodos是最新的todos状态值,返回新数组作为新状态 setTodos(prevTodos => [...prevTodos, todo]); // 新增后清空输入框的可选优化 setTodo(""); }
修复后的完整可运行代码:
import { useState } from 'react'; export default function TodoApp() { const [todo, setTodo] = useState(""); const [todos, setTodos] = useState([]); const handleChange = (e) => { setTodo(e.target.value); } const handleClick = () => { // 空值判断可选,避免添加空内容 if (!todo.trim()) return; setTodos(prevTodos => [...prevTodos, todo.trim()]); setTodo(""); } return( <> <input type="text" value={todo} onChange={handleChange} /> <button onClick={handleClick}>add</button> {/* 可选:渲染待办列表 */} <ul> {todos.map((item, index) => <li key={index}>{item}</li>)} </ul> </> ) }
补充说明:原有代码中console.log(todos)无法打印出更新后的值,是因为React的setState是异步批量执行的,点击事件执行时todos还是旧值,如果需要查看更新后的todos,可以通过useEffect监听todos变化后打印。
内容的提问来源于stack exchange,提问作者voDanh
相关产品推荐
相关产品推荐

