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

React组件挂载调用API后设置定时调用避免重复请求的问题

问题原因

  • useEffect依赖项包含appState.appointmentList、appState.loading,API请求完成后这两个状态都会更新,触发useEffect反复重执行,每次执行都会新增定时器、发起新请求,直接导致重复调用
  • 原请求触发逻辑写反:appState.loading为true时才发起请求,不符合正常的请求发起逻辑
  • 没有做请求互斥处理,可能出现上一个请求未完成、下一个定时请求又发起的并发问题
  • 未适配React18严格模式下useEffect默认执行两次的逻辑,会额外多触发一次初始请求

修复后代码

import fetchAppointments from 'src/redux/asyncThunkApiMethods';
import { useAppDispatch, useAppSelector } from 'src/redux/hooks';
import React, { useEffect, useState, useRef } from 'react';
import { useLocation } from 'react-router-dom';
import { Table, TableHead, TableRow, TableCell, TableBody, Box, Typography } from '@material-ui/core';
import classes from '../../styles/AppointmentList.module.css';

const Appointments = (): JSX.Element => {
  const appState = useAppSelector((state) => state.appointments);
  const dispatch = useAppDispatch();
  const location = useLocation();
  const [isValid, setIsValid] = useState(false);
  // 请求互斥锁,防止重复发起请求
  const isRequestingRef = useRef(false);

  const bac = location.pathname.split('/')[5];

  // 单独处理isValid状态更新,和请求逻辑分离
  useEffect(() => {
    if (!appState.loading && !appState.errorMessage && appState.appointmentList?.visits?.length) {
      setIsValid(true);
    }
  }, [appState.loading, appState.errorMessage, appState.appointmentList]);

  // 处理初始请求和定时请求,只依赖bac和dispatch
  useEffect(() => {
    // 封装请求方法,加互斥锁
    const fetchData = async () => {
      if (isRequestingRef.current) return;
      isRequestingRef.current = true;
      try {
        await dispatch(fetchAppointments({ bac })).unwrap();
      } catch (err) {
        console.error('请求预约列表失败', err);
      } finally {
        isRequestingRef.current = false;
      }
    };

    // 组件挂载后立即发起第一次请求
    fetchData();

    // 设置20秒定时请求
    const interval = setInterval(fetchData, 20000);

    // 组件卸载/bac变化时清理定时器
    return () => {
      clearInterval(interval);
      isRequestingRef.current = false;
    };
  }, [bac, dispatch]);

  // 剩下的渲染逻辑保持不变
  return (
    <div className={classes.root}>
      {/* 原有表格等渲染内容 */}
    </div>
  );
};

export default Appointments;

核心修改点

  • 拆分两个useEffect:一个单独处理isValid状态更新,依赖redux相关状态;另一个单独处理请求逻辑,只依赖bac和dispatch,避免请求逻辑被redux状态变化反复触发
  • 新增useRef实现请求互斥锁,不管是初始请求还是定时请求,只要上一个请求没完成就不会发起新请求,彻底避免重复调用
  • 适配React18严格模式的重复执行逻辑,互斥锁会挡住第二次无效的初始请求
  • 用async thunk的unwrap()方法处理请求异常,避免未捕获的报错中断代码执行
  • 定时器逻辑和请求逻辑解耦,每次定时执行都会先判断请求状态,不会并发调用接口

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:36:00