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

React中fetch重复执行导致文本框数据被覆盖的解决方法

问题分析与解决方案

核心问题拆解

你的代码里有几个关键错误,直接导致了数据被修改/清除、请求逻辑异常的问题:

  • useNavigate 使用错误:仅赋值了useNavigate函数本身,未调用它获取导航实例,导致404场景下无法正常跳转
  • Fetch 异步逻辑错误:将then的返回值(setDocument的执行结果,为undefined)赋值给res,无法正确判断响应状态;且未先校验响应合法性就解析JSON
  • ReactQuill 状态更新错误:onChange回调接收的是编辑后的markdown字符串,但你直接用它覆盖了原本的document对象,导致后续document?.markdown变为undefined,编辑器内容被清空
  • 缺少请求取消机制:组件卸载或params.id变化时,旧请求仍可能完成并更新状态,引发异常

修正后的代码

import React, { useState, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
import DocumentLayout from "../components/DocumentLayout";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";

const EditDocument = () => {
  const params = useParams();
  // 正确调用useNavigate获取导航函数
  const navigate = useNavigate();

  const [loading, setLoading] = useState(true);
  // 明确初始状态结构,避免类型混乱
  const [document, setDocument] = useState({ markdown: "" });

  useEffect(() => {
    // 创建AbortController用于取消请求
    const abortController = new AbortController();
    const signal = abortController.signal;

    const fetchDocument = async () => {
      try {
        const response = await fetch(
          `http://127.0.0.1:8080/markdown?id=${params.id}`,
          { signal } // 关联取消信号
        );

        // 先处理HTTP状态码
        if (response.status === 404) {
          navigate("/");
          return;
        }

        if (!response.ok) {
          throw new Error(`请求失败: ${response.status}`);
        }

        const docData = await response.json();
        setDocument(docData);
      } catch (error) {
        // 忽略取消请求的错误
        if (error.name !== "AbortError") {
          console.error("获取文档失败:", error);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchDocument();

    // 组件卸载或依赖变化时取消请求
    return () => abortController.abort();
  }, [params.id, navigate]);

  // 正确更新document对象的markdown属性,而非覆盖整个对象
  const handleQuillChange = (markdown) => {
    setDocument(prev => ({ ...prev, markdown }));
  };

  return loading ? (
    <h3>Loading...</h3>
  ) : (
    <DocumentLayout>
      <ReactQuill
        theme="snow"
        value={document.markdown}
        onChange={handleQuillChange}
      />
      <button className="editor save-icon">Save</button>
    </DocumentLayout>
  );
};

export default EditDocument;

关键修改说明

  1. 修复useNavigate:调用useNavigate()获取导航函数,确保404时能正确跳转
  2. 重构Fetch逻辑:
    • 使用AbortController取消未完成的请求,避免内存泄漏和旧请求干扰
    • 先校验响应状态码,再解析JSON,正确处理404和请求失败的情况
    • 用try/catch捕获异常,增强代码健壮性
  3. 修正状态更新逻辑:
    • 给document初始状态设置markdown属性,避免undefined导致的编辑器异常
    • handleQuillChange中只更新document对象的markdown属性,保留其他字段,防止状态被覆盖
  4. 完善useEffect依赖:添加navigate到依赖数组,符合React Hooks的规则

额外提示

  • 修复后,只要params.id不变化,useEffect只会执行一次请求;如果params.id变化,旧请求会被自动取消,仅执行新请求
  • 可通过浏览器DevTools的Network标签查看请求实际情况,确认请求次数是否符合预期,区分是真的多次请求还是状态更新导致的界面异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:43:24