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

React新手求助:将Todo添加到Todos对象时遇问题,求排查

Fixing Your Todo App Issues

Hey there! Let's break down what's going wrong in your code and get that todo app working right.

1. You're using an object for todos but trying to use array methods

First off, you initialized todos as an empty object ({}), but map() is a method that only works on arrays. That's why you're seeing an error when trying to render your todos—objects don't have a map function. We need to switch todos to an array instead:

const [todos, setTodos] = useState([]) // Empty array instead of object

2. Your handleClick logic is incorrect

Right now, setTodos({ ...todo, todos }) is creating a new object with the current todo string and the old todos object merged in—this isn't how you add items to a list. We need to update the array by adding the new todo to the end. It's also a good idea to give each todo a unique ID (like a timestamp) so React can track them properly for rendering:

function handleClick(e) {
  e.preventDefault()
  // Don't add empty todos!
  if (!todo.trim()) return
  // Add new todo object with unique ID and text
  setTodos(prevTodos => [...prevTodos, { id: Date.now(), text: todo }])
  // Clear the input after adding
  setTodo("")
}

Using the functional update form (prevTodos => ...) is safer here because it ensures we're always using the latest version of the todos state.

3. Your input isn't a fully controlled component

You have an onChange handler, but you're not binding the input's value to the todo state. This can lead to unexpected behavior. Add the value prop to fix that:

<input 
  onChange={(e) => setTodo(e.target.value)} 
  type="text" 
  placeholder="Add Todo Here"
  value={todo} // Bind input value to state
/>

4. Rendering todos needs a key and proper access

When you map over the todos array, React requires each element to have a unique key prop. Also, if we're storing todo objects (not just strings), we need to render the text property instead of the whole object:

{todos.map((todoItem) => (
  <div key={todoItem.id}>{todoItem.text}</div>
))}

Full Fixed Code

Here's the complete corrected code:

import React, { useState } from "react"
function Content() {
  const [todo, setTodo] = useState("") // todo: user input
  const [todos, setTodos] = useState([]) // todos: array of todo objects
  function handleClick(e) {
    e.preventDefault()
    if (!todo.trim()) return // Skip empty todos
    setTodos(prevTodos => [...prevTodos, { id: Date.now(), text: todo }])
    setTodo("") // Clear input after adding
  }
  return (
    <>
      <h1>Todos</h1>
      <form>
        <input 
          onChange={(e) => setTodo(e.target.value)} 
          type="text" 
          placeholder="Add Todo Here"
          value={todo}
        />
        <button onClick={handleClick}>Add</button>
      </form>
      {todos.map((todoItem) => (
        <div key={todoItem.id}>{todoItem.text}</div>
      ))}
    </>
  )
}
export default Content

A quick side note: Putting console.log(todos) directly in your JSX will run every time the component renders, which can get noisy. If you want to log the todos state, use a useEffect hook that runs when todos changes instead.

内容的提问来源于stack exchange,提问作者babarosa83

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:52:54