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

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))这行代码,核心原因有两个:

  1. Array.push()的返回值是数组修改后的长度(数字类型),不是修改后的数组本身。第一次点击时,初始todos是空数组,执行push后返回值是数字1,调用setTodos(1)会把todos状态从数组替换成数字1。第二次点击时尝试对数字类型的值调用push方法,自然会抛出"push is not a function"的错误。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:48:12