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

React动态输入框onChange收集数组对象的正确实现方法

解决React动态输入框值收集异常问题

问题根源

你的核心问题在于没有将动态输入框与对应的状态索引绑定,且状态更新方式错误:

  • 直接修改newTodo.push():React无法检测到原数组的修改,且每次输入单个字符都会触发push,导致数组记录输入过程而非最终值。
  • setNewTodo([event.target.value]):每次都用新值替换整个数组,最终只会保留最后一个输入框的内容。
  • setNewTodo([...newTodo, event.target.value]):受闭包影响,每次onChange捕获的都是旧的newTodo状态,导致重复叠加旧数组内容。

正确实现方案

不需要单独维护newTodo状态,直接用todoInput数组管理每个输入框的值,提交时再提取有效内容:

  1. 移除冗余状态:删除单独的newTodo状态变量。
  2. 绑定索引更新状态:修改动态输入框的onChange,根据索引更新todoInput对应位置的值(使用函数式更新避免闭包问题)。
  3. 提交时提取有效值:从todoInput中过滤空值,生成最终的待办数组传给Firebase。

修改后的完整代码

const AddTask = () => {
  const db = getFirestore();
  const colTaskRef = collection(db, "Task");
  const [newTitle, setNewTitle] = useState("");
  const [newInCharge, setNewInCharge] = useState("");
  const [newCollabs, setNewCollabs] = useState([]);
  const [newPriority, setNewPriority] = useState("");

  // 直接用todoInput维护每个输入框的值
  const [todoInput, setTodoInput] = useState([{ todo: "" }]);
  
  const handleTodoAdd = () => {
    setTodoInput(prev => [...prev, { todo: "" }]);
  };
  
  const handleTodoRemove = (index) => {
    setTodoInput(prev => prev.filter((_, i) => i !== index));
  };

  const handleSelect = (e) => {
    setNewInCharge(e.target.value);
  };
  
  const handleCheck = (e) => {
    setNewCollabs(prev => [...prev, e.target.value]);
  };

  const handleClick = () => {
    createTask();
  };

  const createTask = async () => {
    // 提取非空的待办项
    const finalTodos = todoInput
      .map(item => item.todo.trim())
      .filter(todo => todo !== "");
      
    await addDoc(colTaskRef, {
      Title: newTitle,
      InCharge: newInCharge,
      Priority: newPriority,
      Todos: finalTodos,
      Collaborators: newCollabs,
      InProgress: false,
      Completed: false,
    });
  };
  
  return (
    <div className="container add__task-container">
      <input
        className="title-input"
        type="text"
        placeholder="Task Title"
        onChange={(event) => setNewTitle(event.target.value)}
      />
      <label htmlFor="selectInCharge"> Who's in charge of this task?</label>
      {<GetCollaborators handleSelect={handleSelect} />}
      <p className="collaborators__checkbox-title">
        Who do you want to collaborate with?
      </p>
      {<GetCollaboratorsCheckBox handleCheck={handleCheck} />}

      <label className="priority-label" htmlFor="priority">
        Priority?
      </label>
      <select
        name="priority"
        className="priority-selector"
        onChange={(event) => setNewPriority(event.target.value)}
      >
        <option value="top"> Top </option>
        <option value="first">First</option>
        <option value="second">Second</option>
        <option value="last">Bottom</option>
      </select>
      <p className="todos__add-title">To Do list:</p>
      {todoInput.map((singleTodo, index) => (
        <div key={index}>
          <input
            type="text"
            className="todo-input"
            value={singleTodo.todo} // 绑定value,成为受控组件
            onChange={(event) => {
              // 函数式更新,确保拿到最新的状态
              setTodoInput(prev => {
                const updatedList = [...prev];
                updatedList[index].todo = event.target.value;
                return updatedList;
              });
            }}
          />
          {todoInput.length - 1 === index && todoInput.length < 5 && (
            <button className="plus-btn" onClick={handleTodoAdd}>
              +
            </button>
          )}
          {todoInput.length > 1 && (
            <button
              className="minus-btn"
              onClick={() => handleTodoRemove(index)}
            >
              -
            </button>
          )}
        </div>
      ))}

      <button className="btn btn__task-submit" onClick={handleClick}>
        Submit Task
      </button>
    </div>
  );
};

关键修改点说明

  • 受控组件绑定:给输入框加上value={singleTodo.todo},确保输入框内容与状态同步。
  • 函数式状态更新:setTodoInput(prev => ...)避免闭包导致的旧状态问题,确保每次更新都基于最新的数组。
  • 提交时过滤空值:避免Firebase存入空字符串的待办项。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:05:47