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

React Todo列表中useState无法更新DOM的问题求助

React Todo列表添加后DOM不更新的问题分析与解决

问题原因

  1. 状态更新依赖同一数组引用:你在AddTodoForm中修改全局dataList数组,随后在update函数里调用setList(dataList)。React的状态更新采用浅比较机制,当传入的数组与原状态数组是同一个引用时,React会判定状态未发生变化,因此不会触发组件重渲染,DOM自然不会更新。
  2. 异步状态更新的误区:setList执行后立刻打印list,由于setState是异步操作,此时输出的仍是更新前的旧值,但这并非DOM不更新的核心原因。
  3. 表单事件重复触发:按钮同时绑定了onClick和表单onSubmit,导致update函数被调用两次,但这也不是DOM不更新的主要诱因。

解决方法

1. 统一状态托管,移除全局数组

遵循React单一数据源原则,将todo列表状态托管在父组件App中,子组件AddTodoForm仅负责收集用户输入,通过回调函数将新todo数据传递给父组件完成状态更新。

2. 使用正确的数组状态更新方式

更新数组状态时,必须创建新的数组引用(如通过展开运算符...),而非直接修改原数组,这样React才能检测到状态变化并触发重渲染。

3. 简化表单提交逻辑

移除按钮的onClick绑定,因为表单的onSubmit会在点击默认类型为submit的按钮时自动触发,避免重复调用更新函数。

修改后的代码示例

App.js

import AddTodoForm from './components/AddTodoForm.js';
import TodoList from './components/TodoList.js';
import { useState } from 'react';

function App() {
  const [list, setList] = useState([]);

  function addTodo(newTodo) {
    // 函数式更新确保获取最新状态
    setList(prevList => [...prevList, newTodo]);
  }

  return (
    <div>
      <AddTodoForm onAddTodo={addTodo} />
      <h1>My Todos</h1>
      <TodoList todos={list} />    
    </div>
  );
}

export default App;

AddTodoForm.js

import { useRef } from 'react';

let idCounter = 1;

function AddTodoForm(props){
    const titleInputRef = useRef();

    function submitHandler(event){
        event.preventDefault();

        const enteredTitle = titleInputRef.current.value.trim();
        if (!enteredTitle) return; // 过滤空输入

        const todoData = {
            text: enteredTitle,
            id: idCounter++,
        };

        props.onAddTodo(todoData);
        // 清空输入框
        titleInputRef.current.value = '';
    }

    return (
        <div className="card">
            <h2>Add New Todos</h2>
            <form onSubmit={submitHandler}>
                <div>
                    <label htmlFor="text">New Todo: </label>
                    <input type="text" required id="text" ref={titleInputRef}></input>
                </div> <br />
                <div>
                    <button className="btn">Add Todo</button>
                </div>
            </form>
        </div>
    )
}

export default AddTodoForm;

TodoList.js(无需修改)

import Todo from './Todo';

function TodoList(props) {
    return (
        <ul>
            {props.todos.map((todo) => (
                <Todo
                    key={todo.id}
                    id={todo.id}
                    text={todo.text}
                />
            ))}
        </ul>
    )
}

export default TodoList;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 12:01:53