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

导航返回TeacherAttend组件时考勤数据重复获取的原因排查

导航返回TeacherAttend组件时重复请求数据的原因及解决方法

核心原因分析

1. AttendenceProvider随路由反复卸载/挂载

你的路由配置中,AttendenceProvider仅包裹了Admin路由的index子路由(path: ""):

{
  path: "/admin",
  element: <PrivateRoute roles={["Admin"]}><Admin /></PrivateRoute>,
  children: [
    {
      path: "",
      element: (
        <AttendenceProvider type="Teacher">
          <Teachersattend />
        </AttendenceProvider>
      ),
    },
    // 其他Admin子路由...
  ]
}

当你导航到其他Admin子路由(比如/admin/teachers)时,Teachersattend组件和它外层的AttendenceProvider会被完全卸载;当你返回/admin时,Provider会重新挂载,触发内部的useEffect再次执行fetchData,导致重复请求。

2. 开发环境下StrictMode的双重渲染

React的StrictMode会在开发环境中强制组件渲染两次(包括useEffect的执行),这会让你看到两次请求,但这个问题仅存在于开发环境,生产环境不会出现。不过这不是导航返回重复请求的根本原因。

3. 组件本地状态与Context的冗余同步

Teacherattend组件中用本地useState初始化了teacherList和AttendenceData,但没有监听Context数据的更新,这不仅会导致本地状态与Context不同步,还会增加不必要的渲染开销,但不是重复请求的直接原因。


解决方案

1. 提升AttendenceProvider到更高层级

将AttendenceProvider移动到Admin路由的根元素中,让它在整个Admin路由生命周期内保持挂载状态:

// 修改Admin路由配置
{
  path: "/admin",
  element: (
    <PrivateRoute roles={["Admin"]}>
      <AttendenceProvider type="Teacher">
        <Admin />
      </AttendenceProvider>
    </PrivateRoute>
  ),
  children: [
    { path: "", element: <Teachersattend /> },
    { path: "teachers", element:<AdminTeachers />},
    // 其他子路由保持不变...
  ],
}

这样切换Admin子路由时,AttendenceProvider不会被卸载,内部的状态和数据会被保留,返回时不会重新请求。

2. 添加数据缓存逻辑(可选)

如果需要确保即使Provider重新挂载(比如页面刷新)也不会重复请求,可以在AttendenceProvider中添加缓存判断:

// 在AttendenceProvider中添加ref跟踪请求状态
const hasFetched = useRef(false);

const fetchData = useCallback(async () => {
  // 已请求过则直接返回
  if (hasFetched.current) return;
  hasFetched.current = true;

  if (type === "Teacher") {
    let teacherData = await getRequest("http://localhost:5000/api/getTeacher");
    teacherData = Object.values(teacherData.data).flat();
    let attendData = await sendJSONRequest(
      "http://localhost:5000/api/getAttendence",
      { type: type }
    );
    attendData = Object.values(attendData.data).flat();
    processData(teacherData, attendData);
  } else if (type === "Student") {}
}, [type]);

3. 移除组件内的冗余本地状态

将Teacherattend中的本地状态逻辑迁移到AttendenceContext中,直接使用Context数据:

// 修改Teacherattend组件
const Teacherattend = React.memo(() => {
  const { list, attendence, updateAttendenceStatus } = useContext(AttendenceContext);

  // 移除本地state,直接使用Context数据
  const handleStatus = (attendeId) => {
    // 调用Context中的方法更新状态
    updateAttendenceStatus(attendeId);
  };

  // ...其他逻辑保持不变

  return (
    <div className="py-6 px-2 lg:px-4 bg-white shadow-md rounded-lg">
      {list.length !== 0
        ? <Attendance
            name="Teacher Attendance"
            data={list}
            onStatusChange={handleStatus}
          />
        : "Loading.."}
      {/* ...其他元素 */}
    </div>
  );
});

同时在AttendenceProvider中添加updateAttendenceStatus方法:

const AttendenceProvider = ({ children, type }) => {
  // ...原有状态

  const updateAttendenceStatus = useCallback((attendeId) => {
    setList(prevList => 
      prevList.map(data => 
        data.attendeId === attendeId 
          ? { ...data, status: data.status === "Present" ? "Absent" : "Present" }
          : data
      )
    );
  }, []);

  const Data = useMemo(() => ({
    list,
    attendence,
    updateGrade,
    updateAttendenceStatus
  }), [list, attendence, updateGrade, updateAttendenceStatus]);

  // ...原有返回逻辑
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:28:09