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

React Todo应用动态修改待办项名称报错问题求助

解决React Todo应用中动态修改待办项名称的问题

我来帮你梳理下问题所在,然后一步步解决它:

核心问题分析

你遇到的TypeError: Cannot read property 'map' of undefined错误,本质是因为修改待办项时,错误地把todoItem数组替换成了单个值,导致子组件Hello接收的todos变成非数组类型,调用map时直接报错。另外,你的待办项存储结构也有问题,导致无法通过id正确定位到要修改的项。

具体修复步骤

1. 修正待办项的存储结构

原来你把待办项存成了纯字符串数组,每个项没有id属性,后续根本没法通过id找到对应项。需要改成对象数组,每个对象包含唯一id和待办文本name:

addTodoHanlder = event => {
  let todoValue = this.state.todoText;
  if (!todoValue.trim()) return; // 避免添加空白待办项
  let incID = this.state.id + 1;
  // 将字符串改为带id和name的对象存入数组
  this.setState({
    todoItem: [...this.state.todoItem, { id: incID, name: todoValue }],
    id: incID
  });
  this.clearTodoText();
};

2. 修正子组件Hello的渲染逻辑

现在每个todo是对象,需要渲染它的name属性,同时要把key放在循环的最外层元素上(符合React的key使用规则):

const Hello = props => {
  return (
    <div>
      <ul>
        {props.todos.map((todo) => {
          return (
            // key必须放在循环的最外层元素上,且保证唯一
            <div key={todo.id}>
              {/* 渲染待办项的文本内容 */}
              <p>{todo.name}</p>
              {/* 给input设置默认值,方便用户修改 */}
              <input
                type="text"
                defaultValue={todo.name}
                onChange={(event) => props.changed(event, todo.id)}
              />
            </div>
          );
        })}
      </ul>
    </div>
  );
};

3. 修正待办项修改逻辑

之前你错误地把整个todoItem数组替换成了单个字符串,现在要遵循React的state不可变原则,正确生成新数组并修改对应项:

todoNameChangeHandler = (event, id) => {
  let todoVal = event.target.value;
  // 通过id找到对应待办项的索引
  const todoIndex = this.state.todoItem.findIndex(el => el.id === id);
  // 确保找到对应项再执行修改
  if (todoIndex !== -1) {
    // 复制整个待办数组(不能直接修改原state数组)
    const updatedTodos = [...this.state.todoItem];
    // 复制对应待办项并修改name属性
    updatedTodos[todoIndex] = { ...updatedTodos[todoIndex], name: todoVal };
    // 更新state
    this.setState({ todoItem: updatedTodos });
  }
};

完整修正后的代码

const Hello = props => {
  return (
    <div>
      <ul>
        {props.todos.map((todo) => {
          return (
            <div key={todo.id}>
              <p>{todo.name}</p>
              <input
                type="text"
                defaultValue={todo.name}
                onChange={(event) => props.changed(event, todo.id)}
              />
            </div>
          );
        })}
      </ul>
    </div>
  );
};

class App extends React.Component {
  state = {
    todoItem: [],
    todoText: "",
    id: 0
  };

  addTodoHanlder = event => {
    let todoValue = this.state.todoText;
    if (!todoValue.trim()) return; // 空内容不添加
    let incID = this.state.id + 1;
    this.setState({
      todoItem: [...this.state.todoItem, { id: incID, name: todoValue }],
      id: incID
    });
    this.clearTodoText();
  };

  clearTodoText() {
    this.setState({ todoText: "" });
  }

  handleChange = event => {
    this.setState({ todoText: event.target.value });
  };

  todoNameChangeHandler = (event, id) => {
    let todoVal = event.target.value;
    const todoIndex = this.state.todoItem.findIndex(el => el.id === id);
    if (todoIndex !== -1) {
      const updatedTodos = [...this.state.todoItem];
      updatedTodos[todoIndex] = { ...updatedTodos[todoIndex], name: todoVal };
      this.setState({ todoItem: updatedTodos });
    }
  };

  render() {
    return (
      <div>
        <input
          type="text"
          placeholder="Enter Todo"
          value={this.state.todoText}
          onChange={this.handleChange}
        />
        <button onClick={this.addTodoHanlder}>AddTodo</button>
        <Hello todos={this.state.todoItem} changed={this.todoNameChangeHandler} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

额外优化说明

  • 添加了空白内容判断,避免用户添加无意义的空待办项
  • 给修改用的input设置了defaultValue,打开时自动显示当前待办项内容,更符合用户修改习惯

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:14:52