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

React项目Fetch仅触发一次/需开开发者工具加载地图标记问题排查

地图标记加载异常问题排查与解决

我正在开发一个网站,需要从MongoDB获取报告数据,根据报告位置在地图上生成标记。当前遇到的问题:

  • 本地环境:仅首次打开网站时会触发Fetch请求,后续刷新不再触发
  • 线上环境:有时完全不触发Fetch,只有打开开发者工具后标记才会显示

已尝试移除所有console.log、安装nocache处理缓存,但问题仍未解决。以下是相关代码:

前端Fetch代码

const [markers, setMarkers] = useState<Array<GeoReport>>([]);
const fetchReports = async () => {
    const response = await fetch(process.env.REACT_APP_BACKEND + '/api/report');
    const json = await response.json();
    json.forEach((report: GeoReport) => {
        markers.push({
            id: report.id,
            lat: report.lat,
            lng: report.lng,
            adress: report.adress,
            placeId: report.placeId,
            surveys: report.surveys,
            fileName: report.fileName,
            imgName: report.imgName
        });
    });
    setMarkers([...markers]);
    dispatch.setMap(
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        markers.reduce((acc: any, curr: any) => {
            (acc[curr.adress] = acc[curr.adress] || []).push(curr);
            return acc;
        }, {} as { [key: string]: GeoReport[] }),
    );
};

后端服务代码

import express from 'express';
import * as Colors from 'colors.ts';
import cors from 'cors';
import bodyParser from 'body-parser';
import nocache from 'nocache';

import { connectDB } from './database/db';
import { errorHandler } from './middleware/errorMiddleware';
import { FRONTEND_URL, PORT } from './utils/config';
import reportRoutes from './routes/reportRoutes';
import driveRoutes from './routes/driveRoutes';
import driveImageRoutes from './routes/driveImageRoutes';
// Apply Colors to consoleLogs
Colors.colors('', '');

// Connection to DB
export const db = async (): Promise<void> => {
    await connectDB();
};

void db();

const app = express();
app.use(
    bodyParser.urlencoded({
        extended: true,
    })
);
app.use(nocache());
app.set('etag', false);

const allowedOrigins = FRONTEND_URL;

app.use(
    cors({
        origin: allowedOrigins,
    })
);
app.use(express.json());

app.use((req, res, next) => {
    //console.log(req.path, req.method);
    next();
});

app.use('/api/report', reportRoutes);
app.use('/api/drive', driveRoutes);
app.use('/api/driveimage', driveImageRoutes);

app.use(errorHandler);

app.listen(PORT, () =>
    console.log(`App listening on port ${PORT}`.green.underline.bold)
);

路由代码(reportRoutes)

import express from 'express';

import {
    getAllreportsHandler,
    createreportHandler,
    getreportHandler,
} from '../controllers/reportController';
const reportRoutes = express.Router();

reportRoutes.route('/').get(getAllreportsHandler).post(createreportHandler);
reportRoutes.route('/:id').get(getreportHandler);

export default reportRoutes;

问题原因分析

  1. 状态更新逻辑错误:直接修改useState返回的原始数组markers.push(),React无法检测状态变化,导致后续刷新时组件无法触发数据更新;同时setMarkers([...markers])依赖异步更新的旧状态,容易出现数据不同步。
  2. Fetch缓存未彻底禁用:后端的nocache配置可能未覆盖浏览器默认缓存策略,线上环境浏览器缓存机制更严格,导致请求被缓存拦截。
  3. 请求触发时机不明确:未看到fetchReports的调用逻辑(如是否在useEffect中执行),若仅在组件首次挂载时调用,后续刷新或路由切换不会重新请求;而打开开发者工具时浏览器会自动禁用缓存,因此能获取到新数据。

解决办法

1. 修复前端状态更新逻辑

禁止直接修改useState返回的状态变量,基于接口返回数据创建新数组:

const fetchReports = async () => {
    try {
        const response = await fetch(process.env.REACT_APP_BACKEND + '/api/report', {
            // 显式禁用缓存
            headers: {
                'Cache-Control': 'no-cache, no-store, must-revalidate',
                'Pragma': 'no-cache',
                'Expires': '0'
            }
        });
        if (!response.ok) throw new Error(`请求失败:${response.status}`);
        
        const json = await response.json();
        // 基于接口数据生成新标记数组
        const newMarkers = json.map((report: GeoReport) => ({
            id: report.id,
            lat: report.lat,
            lng: report.lng,
            adress: report.adress,
            placeId: report.placeId,
            surveys: report.surveys,
            fileName: report.fileName,
            imgName: report.imgName
        }));
        
        setMarkers(newMarkers);
        // 使用新数组生成地图数据,避免依赖旧状态
        dispatch.setMap(
            newMarkers.reduce((acc: any, curr: any) => {
                (acc[curr.adress] = acc[curr.adress] || []).push(curr);
                return acc;
            }, {} as { [key: string]: GeoReport[] }),
        );
    } catch (err) {
        console.error('获取报告数据失败:', err);
    }
};

2. 确保请求触发时机正确

在组件中使用useEffect调用fetchReports,根据需求设置依赖项:

useEffect(() => {
    fetchReports();
}, []); // 空数组表示仅组件挂载时执行一次;若需刷新时也执行,可添加如`location.pathname`等依赖

3. 强化后端缓存控制(可选)

在getAllreportsHandler中显式设置缓存头,确保响应不被缓存:

// 在reportController的getAllreportsHandler函数中
const getAllreportsHandler = async (req, res) => {
    try {
        const reports = await Report.find();
        // 设置缓存控制头
        res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
        res.setHeader('Pragma', 'no-cache');
        res.setHeader('Expires', '0');
        res.status(200).json(reports);
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
};

内容的提问来源于stack exchange,提问作者Ana Cláudia Faria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 19:50:31