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

React待办应用新增Todo项无刷新即时显示实现方法

问题原因

你当前实现中待办列表状态todo存储在App组件内,仅在组件首次挂载时通过useEffect触发一次接口拉取。Write组件完成新待办提交后,既没有重新拉取最新全量列表,也没有将新创建的待办项同步更新到App组件的todo状态中,React检测不到状态变化自然不会重渲染页面,必须手动刷新触发首次加载逻辑才能看到新条目。
除此之外你的代码还有几个显性问题:

  • App组件中渲染列表时写的是<Task Todor={todo} />,但你定义的列表组件名为Todos,命名不匹配会直接抛出组件未定义错误
  • Write组件提交成功后执行setInputText(""),但inputText初始值是对象类型{title: ""},直接赋值为字符串会导致后续输入时展开操作报错
  • Write组件中setInputText(inputText)是无效冗余代码,没有实际作用
  • 输入框没有绑定value属性,状态重置时会出现视图和数据不同步的问题
修复方案

二选一即可,小数据量场景推荐用方案1,逻辑简单不容易出问题;待办项多、追求性能用方案2。

方案1:新增成功后重新拉取全量列表

核心逻辑是把App组件内的拉取列表方法透传给Write组件,新增成功后直接调用触发列表刷新。
首先修改App组件:

function App() {
  const [todo, setTodo] = useState([]);
  async function getTodo() {
    try {
      const todoRes = await axios.get("http://localhost:5000/api/todos");
      setTodo(todoRes.data);
    } catch (error) {
      console.log("获取待办列表失败", error);
    }
  }

  useEffect(() => {
    getTodo();
  }, []);

  return (
    <div className="App">
      <h1>My Todo List</h1>
      <h2>My Todo List</h2>
      {/* 修正组件名错误,将刷新方法透传给Write组件 */}
      <Todos Todor={todo} />
      <Write onAddSuccess={getTodo} />
    </div>
  );
}

export default App;

再修改Write组件:

export default function Write({ onAddSuccess }) {
  const [inputText, setInputText] = useState({
    title: ""
  });

  function handleChange(e) {
    setInputText({
      ...inputText,
      [e.target.name]: e.target.value,
    });
  }

  async function addItem(e) {
    e.preventDefault();
    // 拦截空内容提交
    if (!inputText.title.trim()) return
    try {
      await axios.post("http://localhost:5000/api/todos", inputText);
      // 重置输入框时保持和初始值一致的对象格式
      setInputText({title: ""});
      // 调用父组件方法刷新列表
      onAddSuccess?.();
    } catch (error) {
      console.log("新增待办失败", error);
    }
  }

  return (
    <div className="container">
      <div className="form">
        {/* 绑定value属性保证状态和视图同步 */}
        <input onChange={handleChange} type="text" name="title" value={inputText.title} />
        <button onClick={addItem}>
          <span>Add</span>
        </button>
      </div>
    </div>
  );
}

方案2:新增成功后直接追加新条目到本地状态

不需要二次请求拉取全量列表,性能更好,注意需要确保post接口返回新创建的完整待办对象。
修改App组件:

function App() {
  const [todo, setTodo] = useState([]);
  async function getTodo() {
    try {
      const todoRes = await axios.get("http://localhost:5000/api/todos");
      setTodo(todoRes.data);
    } catch (error) {
      console.log("获取待办列表失败", error);
    }
  }

  useEffect(() => {
    getTodo();
  }, []);

  return (
    <div className="App">
      <h1>My Todo List</h1>
      <h2>My Todo List</h2>
      <Todos Todor={todo} />
      {/* 把状态更新方法透传给Write */}
      <Write setTodoList={setTodo} />
    </div>
  );
}

export default App;

修改Write组件:

export default function Write({ setTodoList }) {
  const [inputText, setInputText] = useState({
    title: ""
  });

  function handleChange(e) {
    setInputText({
      ...inputText,
      [e.target.name]: e.target.value,
    });
  }

  async function addItem(e) {
    e.preventDefault();
    if (!inputText.title.trim()) return
    try {
      const res = await axios.post("http://localhost:5000/api/todos", inputText);
      // 将接口返回的新待办追加到列表头部,需要新条目放尾部就改成[...prev, res.data]
      setTodoList(prev => [res.data, ...prev]);
      setInputText({title: ""});
    } catch (error) {
      console.log("新增待办失败", error);
    }
  }

  return (
    <div className="container">
      <div className="form">
        <input onChange={handleChange} type="text" name="title" value={inputText.title} />
        <button onClick={addItem}>
          <span>Add</span>
        </button>
      </div>
    </div>
  );
}

注意:如果你的post接口没有返回新创建的待办完整字段(比如后端生成的id、创建时间等),不要用方案2,优先选方案1避免后续操作因为字段缺失报错。

内容的提问来源于stack exchange,提问作者The Tech Guy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:15:19